3

Current setting: In the same PHP document I have a PHP randomizer function and the HTML that calls that function -- a separate txt document with strings that are called by the php function:

Function

<?php
function rand_line($fileName, $maxLineLength = 4096) {
  $handle = @fopen($fileName, "strings.txt");
  if ($handle) {
    $random_line = null;
    $line = null;
    $count = 0;
    while (($line = fgets($handle, $maxLineLength)) !== false) {
      $count++;
      if(rand() % $count == 0) {
        $random_line = $line;
      }
    }
    if (!feof($handle)) {
      echo "Error: unexpected fgets() fail\n";
      fclose($handle);
      return null;
    } else {
      fclose($handle);
    }
    return $random_line;
  }
}
?>

I call the function in the HTML using:

<?php echo rand_line("strings.txt");?>
<input type="button" value="Another String" onClick="window.location.reload()">

This tends to be slow when multiple users access the page and press the button to obtain a new status.

What I would like to achieve:

Improve the performance and make the whole thing not so heavy: maybe the randomizer is unnecessarily complicated and I could work with AJAX calls for example, but if possible keeping the string list inside the strings.txt file and separated from the PHP script and HTML.

Sorry if I don't know what I'm talking about... I'm not a proficient programmer. Just a guy that hacks stuff together once in a while :)

7
  • Would an answer that separates both your function and the HTML codes be acceptable for you? Commented Apr 15, 2016 at 14:13
  • Is strings.txt ever-changing? In that, is it a static file that never changes? Or is the file constantly being updated with new strings? And how many lines/*strings* are in the file? Commented Apr 15, 2016 at 14:18
  • See this answer for a much more efficient example of getting a random line from a file, assuming your file is not tremendously large (doubt you will run into memory problems in your use case). Your algorithm for doing so is indeed rather roundabout, doing unnecessary iteration (could at the very least stop when something is found), and unnecessary work every iteration (new random number every time, checking if divisible with line number...) Commented Apr 15, 2016 at 14:29
  • @PatrickGregorio yes, definitely :) Commented Apr 15, 2016 at 14:36
  • @Marcus it might change, new strings can be added eventually. At the moment the file has around 15 strings, but I don't think it will ever reach 100 for ex. Commented Apr 15, 2016 at 14:37

3 Answers 3

1

You really don't want to use window.location.reload(); That is terrible... You do not want to refresh a page...

location.reload() sends http request for a whole new page (whole HTML), and then not only that your browser needs to render whole HTML again, you have to transfer more duplicated data through a network, from point A to point B.

You should send HTTP request only for a data that you need (you don't need whole HTML again, you loaded it the 1st time you visited page).

Instead, use XMLHttpRequest javascript library (AJAX) to request only for a portion of data (in your case => random line string)

HTML:

<!DOCTYPE html>
<html>
<head lang="en">
    <script type="text/javascript">
        function loadDoc(url, cfunc) {
            var xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = function () {
                if (xhttp.readyState == 4 && xhttp.status == 200) {
                    cfunc(xhttp);
                }
            };
            xhttp.open("GET", url, true)
            xhttp.send();
        }


        function randomLine(xhttp) {
            alert(xhttp.responseText);
        }
    </script>

</head>
<body>

<input type="button" value="Get random line" onClick="loadDoc('http://localhost:8080/myScript.php', randomLine)">

</body>
</html>

PHP:

myScript.php

<?php 
function rand_line($fileName, $maxLineLength = 4096) 
{ 
   ... 
}
echo rand_line("strings.txt");        
?>
Sign up to request clarification or add additional context in comments.

12 Comments

@Marcus I don't see any reason why would I reload a whole page? Can you give some? By doing so, even if everything is cached, and there is no aditional data on network, the browser still needs to render HTML and onload-javascript, and if there is a lot of tags, it will defenitly noticeably slow the page.
Why would you want to spend extra resources when it's completly unnecessary. You will never know how good hardware your client has. What if he has 10 years old pc, opening in some obsolete browser... for him it might be 2 seconds, not 0.5. Yes ofc, there could be a 100k lines in the string.txt file, but I was just assuming its normal size file. The one upgrade that will definetly increase performance is using ajax... so...
@Marcus Another notice is that users dont like to wait for the page to respond. They hate it. By using AJAX, we asynchronously ask for the data while user can still use the other parts of page.
Another example could be a network problem, and it took 4 seconds to load the page. The result would be: user staring 4 seconds in a blank page.
I'm not sure that you understand, of course it would take ajax call 4 seconds also, but since it is async, the user might not notice it, and continue to use parts of page that doesn't need data from server.
|
1

*EDIT #2*

Fully-functioning script. Grabs initial strings via PHP, and stores in array for later JavaScript usage. Minimizes # of calls.

PHP to grab strings from file; generates a default (random) string, as well as an array of strings for later use with button.

/**
 * @input array $file
 * @return array (mixed) [0] => string, [1] => array
 */
$randomStringFromFile = function($file) {
    if (!$file) return false;

    /**
     * @return Removes carriage returns from the file
     *         and wraps $val with single-quotes so as
     *         to not break JavaScript
     */
    $add_quotes = function(&$val) {
        return str_replace("\n", "", "'$val'");
    };
    return [$file[rand(0, count($file)-1)], array_map($add_quotes, $file)];
};
$randomString = $randomStringFromFile( @file('strings.txt') ) ?: false;

JavaScript

<div id="string_container"><?php echo $randomString[0]; // defaults random string to page ?></div><br>
<button onclick="getString();">Another String</button>
<script>
var getString = function() {
    var arr = [<?php echo implode(',', $randomString[1]); ?>],
        setString = document.getElementById('string_container').innerHTML = arr[Math.floor(Math.random() * arr.length)];
};
</script>

Place the above in your page and you should be good to go.

EDIT (ORIGINAL)

We can remove PHP from the equation entirely using the following (fastest method):

<div id="string_container"></div><br>
<button onclick="getString();">Another String</button>
<script>
var getString = function() {
    var request = new XMLHttpRequest(),
        file = 'strings.txt';

    request.open('GET', file);
    request.onload = function() {
        if (request.status === 200) {
            var arr = request.responseText.split("\n"), /** assuming line breaks in file are standard carriage returns (Unix); "\r" if Windows */
                setString = document.getElementById('string_container').innerHTML = arr[Math.floor(Math.random() * arr.length-1)];
        }
    };
    request.send();
};
</script>

ORIGINAL w/PHP

We can simplify the PHP even further, removing loops from the equation altogether.

$randomStringFromFile = function($file) {
    if (!$file) return false;
    return $file[rand(0, count($file)-1)];
};
echo $randomStringFromFile( @file('strings.txt') ) ?: 'No worky!';

Using file() will return the contents in an array, thus allowing you to simply select a key at random and return the value.

NOTE On average, $file[rand(0, count($file)-1)] outperformed array_rand() (E.g. $file[array_rand($file)];) when selecting a key at random. By negligible amounts, have you.. ~0.0002s vs ~0.0005s, respectively.

Comments

0

You can simplify your code

function rand_line($fileName, $maxLineLength = 4096) {
    $f = file($fileName);
    $length = $maxLineLength + 1;

    do {
        $line = $f[array_rand($f)];
        $length = strlen($line);
    } while ($length > $maxLineLength);

    return $line;
}

1 Comment

do {} while (0);, really

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.