简体   繁体   中英

Call output of a PHP randomizer via AJAX

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 :)

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");        
?>

* 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() (Eg $file[array_rand($file)]; ) when selecting a key at random. By negligible amounts, have you.. ~0.0002s vs ~0.0005s , respectively.

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM