PHP slow if requested with AJAX? - php

I made a simple Webpage with an empty form Tag. This Tag is filled with the response of an AJAX request. The request asks a PHP script for data. This script returns its execution time. Now there is something really odd. If I type in the address by hand then the script tells me
<!-- Duration: 0.8 milliseconds (~1242 pages per second) -->
But if I use the build-in network request logger of Chrome (for watching what has been loaded) then I got this
<!-- Duration: 52.7 milliseconds (~19 pages per second) -->
Any ideas why it is 80 times slower?
I repeat: Same script, same parameter, identical response (but the duration time of cause), same server, different request types: AJAX and browser address line.
<?php
class AbstractModule
{
final function __construct(..)
{
// for measuring creation time
$this->starttime = microtime(true);
}
public final function return_duration()
{
$duration = (microtime(true) - $this->starttime) * 1000;
return "\n<!-- Duration: " . number_format($duration, 1, '.', '') . " milliseconds (~" . number_format(1000 / $duration, 0, '.', '') . " pages per second) -->";
}
}
$demo = new AbstractModule();
// doing very much :)<
echo $demo->return_duration();
?>
Thanks.

Do you use sessions? The difference might be that the ajax request restarts a session each time, because you don't send any cookies along.
Otherwise, I suggest you break out a debugger and track down the culprit.

Related

Upload speed test

I'm developing an app with Laravel and VueJs, which should make upload speed tests.
To do this, I already had in my Vue component a script recording a few minutes of webCam, and upload it to the server via a Form included in axios post request.
To calculate the transfer speed, in my php Controller, I get the current timestamp, also timestamp of sending the request and the content length of my http request.
The speed should be speed = length / time
But unfortunately, the results are so far from the real speed when i did tests in some websites testSpeed because of the request time that is not correct.
In Chrome inspection through the network, i see several times, as "request sent", "waiting ttfb", "content download" and more... I think that the time corresponding to the request time sent is the "request sent", but i have not idea how to got it in my php script.
here are screenshots of my script and the result:
public function analyse(Request $request)
{
$currentTimestamp = round(microtime(true) * 1000);
$requestSentAt = round($request->server->get('REQUEST_TIME_FLOAT') * 1000);
$deliveryTime = ($currentTimestamp - $requestSentAt) / 1000;
$contentLength = $request->server->get('CONTENT_LENGTH') / 1000000;
$speed = $contentLength / $deliveryTime;
dd($speed." Mo/S");
}
Chrome debugger
result
Do you think that my logic doing this calculus is right ?
Do you have an idea or suggestion ?
I'm really blocked in this step.
I really appreciate your help in advance.
Thank you very much and have a good day .

In PHP, how to stop function, wait, and recursively restart itself until some condition is met?

If some condition is met, how can I make the function:
Stop executing the rest of the function
Wait X time
Restart the function
Would it be something like:
function someFunc() {
if (x == 0) {
sleep(60);
someFunc();
return;
}
...other code only to be run if above is false...
}
someFunc();
...other code only to be run if above function finishes running completely...
In case its relevant and there is some library to handle APi limits or something, I am doing this for an API connection. First I receive a webhook hit via
file_get_contents('php://input')
which contains a URL. Then I hit the URL with
file_get_contents( $url )
and, after parsing $http_response_header into a $headers array, check it's header as if ($header['api_limit'] == 0) ... (in the above example this is x). If "x" is 0, then I want the function to wait a minute until the limit cycle resets and run the second file_get_contents( $url ) and the parsing that follows it again.
The main reason I wanted to handle it this way is to not have to record anything. The webhook I receive via file_get_contents('php://input') only happens once. If API rate limit is hit and I try to use the URL in the webhook but fail, then the URL is lost. So I was hoping the function would just wait X time until the rte resets until trying to use the webhook-received URL with file_get_contents($url) again. Is this bad practice somehow?
With rate limited resources you usually want to cache a copy of the data for blocks of X minutes so that the limit is never actually exceeded. For example, in the case of a maximum of 10 requests per hour you would cache the response for at least 6 minutes before attempting fetch a new response.
It is not a good idea to stall the entire PHP interpreter until the rate limit is lifted.
As for approaching "repeat an attempt to do something until it works" in general, this is not something that PHP handles very well given you usually want a request and response cycle with PHP to be as fast as possible so it can move onto the next request. Your PHP application should provide an immediate yes/no response to an external utility that triggers the task at a given interval.
I solved it like this:
// This will be the testing variable, where in the actual script
// we'll check the response code of file_get_contents
$count = 0;
function funcTwo( &$count ) {
// Here I'd run file_get_contents and parse the headers
$count = ++$count;
echo "functTwo() running $count... \n";
// Here I'll test for response code 429, if true, restart
if ($count !== 5) {
echo "Count only = $count so we're gonna take a nap... \n";
sleep(1);
echo "Waking from sleep $count and rerunning myself... \n";
funcTwo($count);
return;
}
echo "Count finally = $count, exiting funcTwo... \n";
}
// This function does the main work that relies on the successful response from
function funcOne( $count ) {
echo "functOne() running! \n";
// The function will be delayed here until a successful response is returned
funcTwo($count);
echo "Count finally = $count, so now we can finally do the work that \n";
echo "depends on a successful response from funcTwo() \n";
// Do main work
echo "Work done, exiting funcOne and script... \n";
}
funcOne($count);

creating schedule task without Cron job

Scheduled task needs to be created but its not possible to use Cron job (there is a warning from hosting provider that "running the cron Job more than once within a 45-minute period is a infraction of their rules and could result in shutting down the account."
php script (which insert data from txt to mysql database) should be executed every minute, ie this link should be called http://www.myserver.com/ImportCumulusFile.php?type=dayfile&key=letmein&table=Dayfile&file=./data/Jan10log.txt
Is there any other way?
There are multiple ways of doing repetitive jobs. Some of the ways that I can think about right away are:
Using: https://www.setcronjob.com/
Use an external site like this to fire off your url at set intervals
Using meta refresh. More here. You'd to have to open the page and leave it running.
Javascript/Ajax refresh. Similar to the above example.
Setting up a cron job. Most shared hosting do provide a way to set up cron jobs. Have a look at the cPanel of your hosting.
if you have shell access you could execute a php script via the shell
something like this would be an endless loop, that would sleep 60 seconds execute, collect garbage and repeat until the end of time.
while(true) {
sleep(60);
//script here
//end your script
}
or you could do a "poor mans cron" with ajax or meta refresh. i've done it before. basically, you just place a redirect with either javascript or html's meta refresh at the beggining of your script. access this script from your browser, and just leave it open. it'll refresh every 60 seconds, just like a cronjob.
yet another alternative to a cronjob, would be a bash script such as:
#!/bin/bash
while :
do
sleep 60
wget http://127.0.0.1/path/to/cronjob.php -O Temp --delete-after
done
all this being said, you probably will get caught by the host and get terminated anyway.
So your best solution:
go and sign up for a 5-10 dollar a month vps, and say good bye to shared hosting and hello to running your own little server.
if you do this, you can even stop using crappy php and use facebook's hhvm instead and enjoy its awesome performance.
There's a free service at
http://cron-job.org
That lets you set up a nice little alternative.
Option A
An easy way to realize it would be to create a file/database entry containing the execution time of your php script:
<?php
// crons.php
return [
'executebackup.php' => 1507979485,
'sendnewsletter.php' => 1507999485
];
?>
And on every request made through your visitors you check the current time and if its higher you include your php script:
<?php
// cronpixel.php
$crons = #include 'cache/crons.php';
foreach ($crons as $script => $time) {
if ($time < time()) {
// create lock to avoid race conditions
$lock = 'cache/' . md5($script) . '.lock';
if (file_exists($lock) || !mkdir($lock)) {
continue;
}
// start your php script
include($script);
// now update crons.php
$crons[ $script ] += 86400; // tomorrow
file_put_contents('cache/crons.php', '<?php return ' . var_export($crons, true) . '; ?' . '>')
// finally delete lock
rmdir($lock);
}
}
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// image data
$im = imagecreate(1, 1);
$blk = imagecolorallocate($im, 0, 0, 0);
imagecolortransparent($im, $blk);
// image output
header("Content-type: image/gif");
imagegif($im);
// free memory
imagedestroy($im);
?>
Note: It will be rarily called on the exact second, because you do not know when your visitor will open your page (maybe 2 seconds later). So it makes sense to set the new time for the next day not through adding 86400 seconds. Instead use mktime.
Option B
This is a little project I realized in the past, that is similar to #r3wt 's idea, but covers race conditions and works on exact times like a cronjob would do in a scheduler without hitting the max_execution_time. And it works most of the time without the need to resurrect it (as done through visitors in Option A).
Explanation:
The script writes a lock file (to avoid race conditions) for the 15th, 30th, 45th and 60th second of a minute:
// cron monitoring
foreach ($allowed_crons as $cron_second) {
$cron_filename = 'cache/' . $cron_second . '_crnsec_lock';
// start missing cron requests
if (!file_exists($cron_filename)) {
cron_request($cron_second);
}
// restart interrupted cron requests
else if (filemtime($cron_filename) + 90 < time()) {
rmdir($cron_filename);
cron_request($cron_second);
}
}
Every time a lock file is missing the script creates it and uses sleep() to reach the exact second:
if (file_exists($cron_filename) || !mkdir($cron_filename)) {
return;
}
// add one minute if necessary
$date = new DateTime();
$cron_date = new DateTime();
$cron_date->setTime($cron_date->format('H'), $cron_date->format('i'), $sec);
$diff = $date->diff($cron_date);
if ($diff->invert && $diff->s > 0) {
$cron_date->setTime($cron_date->format('H'), $cron_date->format('i') + 1, $sec);
}
$diff = $date->diff($cron_date);
// we use sleep() as time_sleep_until() starts one second to early (https://bugs.php.net/bug.php?id=69044)
sleep($diff->s);
After waking up again, it sends a request to itself through fopen():
// note: filter_input returns the unchanged SERVER var (http://php.net/manual/de/function.filter-input.php#99124)
// note: filter_var is unsecure (http://www.d-mueller.de/blog/why-url-validation-with-filter_var-might-not-be-a-good-idea/)
$url = 'http' . isSecure() . '://' . filter_input(INPUT_SERVER, 'HTTP_HOST', FILTER_SANITIZE_URL) . htmlspecialchars($request_uri, ENT_QUOTES, 'UTF-8');
$context = stream_context_create(array(
'http' => array(
'timeout' => 1.0
)
));
// note: return "failed to open stream: HTTP request failed!" because timeout < time_sleep_until
if ($fp = #fopen($url, 'r', false, $context)) {
fclose($fp);
}
rmdir($cron_filename);
By that it calls itself infinitely and you are able to define different starting times:
if (isset($_GET['cron_second'])) {
if ($cron_second === 0 && !(date('i') % 15)) {
mycron('every 15 minutes');
}
if ($cron_second === 0 && !(date('i') % 60)) {
mycron('every hour');
}
}
Note: It produces 5760 requests per day (4 per minute). Not much, but a cronjob uses much less ressources. If your max_execution_time is high enough you could change it to calling itself only once per minute (1440 requests/day).
I understand that this question is bit old but I stumbled on it a week ago with this very question and the best and secure option we found was using a Web Service.
Our context:
We have our system in both shared hosting and private clouds.
We need that a script is activated once in a month (there are plans to create more schedules and to allow users to create some predetermined actions)
Our system provides access to many clients, so, when anyone uses the system it calls for a Web Service via Ajax and doesn't care about the response (after all everything is logged in our database and must run without user interaction)
What we've done is:
1 - An ajax call is called upon access in any major screen.
2 - The Web Service reads a schedule table on our database and calls whatever needs calling
3 - To avoid many stacked Web Service calls we check datetime with an interval of 10 mins before actually performing any actions
That's also a way to distribute the load balance and the schedules doesn't affect the system with user interaction.

PHP Speed Test for user connection speed without echo in current page

I am looking for a possibility to check the user connection speed. It is supposed to be saved as a cookie and javascript files as well as css files will be adapted if the speed is slow.
The possibility for testing speed i have at the moment ist the following
$kb = 512;
flush();
//
echo "<!-";
$time = explode(" ",microtime());
for($x=0;$x<$kb;$x++){
echo str_pad('', 512, '.');
flush();
}
$time_end = explode(" ",microtime());
echo "->";
$start = $time[0] + $time[1];
$finish = $time_end[0] + $time_end[1];
$deltat = $finish - $start;
return round($kb / $deltat, 3);
While it works, I do not like it to put so many characters into my code also if I echo all this I can not save the result in a cookie because there has already been an output.
Could one do something like this in a different file wor something? Do you have any solution?
Thanks in advance.
Do you have any solution?
My solution is to not bother with the speed test at all. Here's why:
You stated that the reason for the test is to determine which JS/CSS files to send. You have to keep in mind that browsers will cache these files after the first download (so long as they haven't been modified). So in effect, you are sending 256K of test data to determine if you should send, say, an additional 512K?
Just send the data and it will be cached. Unless you have MBs of JS/CSS (in which case you need a site redesign, not a speed test) the download time will be doable. Speed tests should be reserved for things such as streaming video and the like.
The only idea what i can come up is a redirect.
Measure users' speed
Redirect to index
While this isn't a nice solution it only need to measure users' speed only once so i think it's excusable.
How about using javascript to time how long it takes to load a page. Then use javascript to set the cookie.
microtime in javascript http://phpjs.org/functions/microtime:472
Using jQuery
<head>
<!-- include jquery & other html snipped -->
<script>
function microtime (get_as_float) {
// http://kevin.vanzonneveld.net
// + original by: Paulo Freitas
// * example 1: timeStamp = microtime(true);
// * results 1: timeStamp > 1000000000 && timeStamp < 2000000000
var now = new Date().getTime() / 1000;
var s = parseInt(now, 10);
return (get_as_float) ? now : (Math.round((now - s) * 1000) / 1000) + ' ' + s;
}
function setCookie(c_name, value, expiredays) {
var exdate=new Date();
exdate.setDate(exdate.getDate()+expiredays);
document.cookie=c_name+ "=" +escape(value)+
((expiredays==null) ? "" : ";expires="+exdate.toUTCString());
}
start = microtime(true);
$(window).load(function () {
// everything finished loading
end = microtime(true);
diff = end - start;
// save in a cookie for the next 30 days
setCookie('my_speed_test_cookie', diff, 30);
});
</script>
</head>
<body>
<p>some page to test how long it loads</p>
<img src="some_image_file.png">
</body>
Some pitfalls:
- The page would need to start loading first. JQuery would need to be loaded (or you can rework the above code to avoid jQuery)
testing speed on ASCII / Latin data may not give the best result, because the characters may get compressed. Besides the high level gzip compression, Some modems / lines (if not all) have basic compression that is able to detect repeating characters and tell the other end that the next 500 are repeat of ' '. I guess it would be best to use binary data that has been compressed
The problem here is that you can't really solve this nicely, and probably not in pure PHP. The approach you've taken will make the user download (512x512) = 262 144 bytes of useless data, which is much bigger than most complete pages. If the user is on a slow connection, they may assume your site is down before the speed test is over (with 10 kB/sec, it'd take half a minute before anything interesting shows up on screen!).
You could make an AJAX request for a file of a known size and time how long that takes. The problem here is that the page needs to be already loaded for that to work, so it'd only work for subsequent pages.
You could make a "loading" page (like you see on GMail when accessing it from a slow connection) that preloads the data, with a link to the low-bandwidth version (or maybe a redirect if the loading is taking too long).
Or you could save the "start" time in the cookie and make an AJAX request when the page is done loading - that would give you the actual loading time of your page; if that's, say, over 10 seconds, you may want to switch to the low-bandwidth version.
None of these, however, will get you the speed on the very first access; and sending a big empty page up front is not a very good first impression either.
you visit the first page(maybe 100kB with all external files), a session is immeadeatly started with
$_SESSION["start_time"] = time();
when page finished loading(jQuery window load or smth:) u send a request again with time,
u compute the speed (jQueryRequestTime - $_SESSION["start_time"] / PageSize) and set another session variable, the next link he clicks then can include custom css/js approved for that
ofc this is not perfect:)
After you've determined the user's speed, send javascript to the browser to set the cookie and then do a refresh or redirect in cases where the speed is below what you'd like.
The only thing I can think of would be to subscribe to a service which offers an IP to net speed lookup. These services work by building a database of IP addresses and cataloging their registered intended use. They're not always accurate, but they do provide a starting point. Look up the user's IP address against one of these and see what it returns.
Ip2Location.com provides such a database, beginning with their DB13 product.
Of course, if your goal is a mobile version of the site, user agent sniffing is a better solution.

How does session_start lock in PHP?

Originally, I just want to verify that session_start locks on session. So, I create a PHP file as below. Basically, if the pageview is even, the page sleeps for 10 seconds; if the pageview is odd, it doesn't. And, session_start is used to obtain the page view in $_SESSION.
I tried to access the page in two tabs of one browser. It is not surprising that the first tab takes 10 seconds since I explicitly let it sleep. The second tab would not sleep, but it should be blocked by sessiont_start. That works as expected.
To my surprise, the output of the second page shows that session_start takes almost no time. Actually, the whole page seems takes no time to load. But, the page does take 10 seconds to show in browser.
obtained lock
Cost time: 0.00016689300537109
Start 1269739162.1997
End 1269739162.1998
allover time elpased : 0.00032305717468262
The page views: 101
Does PHP extract session_start out of PHP page and execute it before other PHP statements?
This is the code.
<?php
function float_time()
{
list($usec, $sec) = explode(' ', microtime());
return (float)$sec + (float)$usec;
}
$allover_start_time = float_time();
$start_time = float_time();
session_start();
echo "obtained lock<br/>";
$end_time = float_time();
$elapsed_time = $end_time - $start_time;
echo "Cost time: $elapsed_time <br>";
echo "Start $start_time<br/>";
echo "End $end_time<br/>";
ob_flush();
flush();
if (isset($_SESSION['views']))
{
$_SESSION['views'] += 1;
}
else
{
$_SESSION['views'] = 0;
}
if ($_SESSION['views'] % 2 == 0)
{
echo "sleep 10 seconds<br/>";
sleep(10);
}
$allover_end_time = float_time();
echo "allover time elpased : " . ($allover_end_time - $allover_start_time) . "<br/>";
echo "The page views: " . $_SESSION['views'];
?>
That seems to be a firefox related "issue". If you request the same url in two tabs/windows the second request waits until the first request is finished (could also be an addon that blocks the second request, haven't tested that).
Take e.g.
<?php // test.php
$start = microtime(true);
echo "<pre>start: $start</pre>";
sleep(5);
$end = microtime(true);
echo '<pre>', $start, "\n", $end, "\n", $end-$start, '</pre>';
I called it twice and the output was
start: 1269742677.6094
1269742677.6094
1269742682.609
4.9995958805084
and
start: 1269742682.6563
1269742682.6563
1269742687.6557
4.9994258880615
Note that there's already a 5 second gap between the start times.
When called as http://localhost/test.php and http://localhost/test.php?a=b instead of the exact same url twice this does not happen.
Both IE8 and Chrome do not show that behavior.
Yes, This could be because of session_start() blocking other requests in the same session (file based). I was able to verify the issue in Firefox(4.x) and Chrome(10.x) in Windows XP/PHP 5.2 with default session handler(file). I am not sure if this issue is reproducible for non-file session handlers.
obtained lock
**Cost time: 9.90100598335**
Start 1303227658.67
End 1303227668.57
sleep 10 seconds
allover time elpased : 19.9027831554
The page views: 4
This is a very interesting issue and the Firefox tab locking described in the above answer would have eclipsed this one from being detected.
http://www.php.net/manual/en/function.session-start.php#101452
Since php does not have a container. How do two calls to same session get serialized? Who does this? How do the two processes talk? Is PHP module always active and only spawning threads after doing session check? In that case the PHP module is indeed behaving like a container that is, in this case, providing session management service to this extent.

Categories