PHP long poll fails - php

I have this loop to long poll:
$time = time(); //send a blank response after 15sec
while((time() - $time) < 15) {
$last_modif = filemtime("./logs.txt");
if($_SESSION['lasttime'] != $last_modif) {
$_SESSION['lasttime'] = $last_modif;
$logs = file_get_contents("./logs.txt");
print nl2br($logs);
ob_flush();
flush();
die();
}
usleep(10000);
}
problem is: the "if" condition is never entered in the middle of the while loop, even if logs.txt is modified. I have to wait 15sec till the next call to this file to obtain the updated content (so it becomes a regular, "setTimeout style" AJAX polling, not a long-poll). Any idea why ?

This is because of the filemtime() function : its results are cached. Thus each time your loop is executed the timestamp's the same for 15 seconds.
I have not tried it myself, but according to w3cschools :
The result of this function are cached. Use clearstatcache() to clear the cache.
Hope that helps !

Related

Multiupload using pthread in php

I have been trying to implement multi-threading in php to achieve multi-upload using pthreads php.
From my understanding of multi-threading, this is how I envisioned it working.
I would upload a file,the file will start uploading in the background; even if the file is not completed to upload, another instance( thread ) will be created to upload another file. I would make multiple upload requests using AJAXand multiple files would start uploading, I would get the response of a single request individually and I can update the status of upload likewise in my site.
But this is not how it is working. This is the code that I got from one of the pthread question on SO, but I do not have the link( sorry!! ).
I tested this code to see of this really worked like I envisioned. This is the code I tested, I changed it a little.
<?php
error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
public $url;
public $data;
public function __construct ($url) {
$this->url = $url;
}
public function run () {
if ( ($url = $this->url) ){
/*
* If a large amount of data is being requested, you might want to
* fsockopen and read using usleep in between reads
*/
$this->data = file_get_contents ($url);
echo $this->getThreadId ();
} else{
printf ("Thread #%lu was not provided a URL\n", $this->getThreadId ());
}
}
}
$t = microtime (true);
foreach( ["http://www.google.com/?q=". rand () * 10, 'http://localhost', 'https://facebook.com'] as $url ){
$g = new AsyncWebRequest( $url );
/* starting synchronized */
if ( $g->start () ){
printf ( $url ." took %f seconds to start ", microtime (true) - $t);
while ($g->isRunning ()) {
echo ".";
usleep (100);
}
if ( $g->join () ){
printf (" and %f seconds to finish receiving %d bytes\n", microtime (true) - $t, strlen ($g->data));
} else{
printf (" and %f seconds to finish, request failed\n", microtime (true) - $t);
}
}
echo "<hr/>";
}
So what I expected from this code was it would hit google.com, localhost and facebook.com simultaneously and run their individual threads. But every request is waiting for another request to complete.
For this it is clearly waiting for first response to complete before it is making another request because time the request are sent are after the request from the previous request is complete.
So, This is clearly not the way to achieve what I am trying to achieve. How do I do this?
You might want to look at multi curl for such multiple external requests. Pthreads is more about internal processes.
Just for further reference, you are starting threads 1 by 1 and waiting for them to finish.
This code: while ($g->isRunning ()) doesn't stop until the thread is finished. It's like having a while (true) in a for. The for executes 1 step at a time.
You need to start the threads, add them in an array, and in another while loop check each of the threads if it stopped and remove them from the array.

What would cause fastcgi_finish_request to take several seconds to execute?

I have run into a rather strange issue with a particular part of a large PHP application. The portion of the application in question loads data from MySQL (mostly integer data) and builds a JSON string which gets output to the browser. These requests were taking sevar seconds (8 - 10 seconds each) in Chrome's developer tools as well as via curl. However the PHP shutdown handler I had reported that the requests were executing in less than 1 second.
In order to debug I added a call to fastcgi_finish_request(), and suddenly my shutdown handler reported the same time as Chrome / curl.
With some debugging, I narrowed it down to a particular function. I created the following simple test case:
<?php
$start_time = DFStdLib::exec_time();
$product = new ApparelQuoteProduct(19);
$pmatrix = $product->productMatrix();
// This function call is the problem:
$ranges = $pmatrix->ranges();
$end_time = DFStdLib::exec_time();
$duration = $end_time - $start_time;
echo "Output generation duration was: $duration sec";
fastcgi_finish_request();
$fastcgi_finish_request_duration = DFStdLib::exec_time() - $end_time;
DFSkel::log(DFSkel::LOG_INFO,"Output generation duration was: $duration sec; fastcgi_finish_request Duration was: $fastcgi_finish_request_duration sec");
If I call $pmatrix->ranges() (which is a function that executes a number of calls to mysql_query to fetch data and build an in-memory PHP object structure from that data) then I get the output:
Output generation duration was: 0.2563910484314 sec; fastcgi_finish_request Duration was: 7.3854329586029 sec
in my log file. Note that the call to $pmatrix->ranges() does not take long at all, yet somehow it causes the PHP FastCGI handler to take seven seconds to fihish the request. (This is true even if I don't call fastcgi_finish_request -- the browser takes 7-8 seconds to display the data either way)
If I comment out the call to $pmatrix->ranges() I get:
Output generation duration was: 0.0016419887542725 sec; fastcgi_finish_request Duration was: 0.00035214424133301 sec
I can post the entire source for the $pmatrix->ranges() function, but it's very long. I'd like some advice on where to even start looking.
What is it about the PHP FastCGI request process which would even cause such behavior? Does it call destructor functions / garbage collection? Does it close open resources? How can I troubleshoot this further?
EDIT: Here's a larger source sample:
<?php
class ApparelQuote_ProductPricingMatrix_TestCase
{
protected $myProductId;
protected $myQuantityRanges;
private $myProduct;
protected $myColors;
protected $mySizes;
protected $myQuantityPricing;
public function __construct($product)
{
$this->myProductId = intval($product);
}
/**
* Return an array of all ranges for this matrix.
*
* #return array
*/
public function ranges()
{
$this->myLoadPricing();
return $this->myQuantityRanges;
}
protected function myLoadPricing($force=false)
{
if($force || !$this->myQuantityPricing)
{
$this->myColors = array();
$this->mySizes = array();
$priceRec_finder = new ApparelQuote_ProductPricingRecord();
$priceRec_finder->_link = Module_ApparelQuote::dbLink();
$found_recs = $priceRec_finder->find(_ALL,"`product_id`={$this->myProductId}","`qtyrange_id`,`color_id`");
$qtyFinder = new ApparelQuote_ProductPricingQtyRange();
$qtyFinder->_link = Module_ApparelQuote::dbLink();
$this->myQuantityRanges = $qtyFinder->find(_ALL,"`product_id`=$this->myProductId");
$this->myQuantityPricing = array();
foreach ($found_recs as &$r)
{
if(false) $r = new ApparelQuote_ProductPricingRecord();
if(!isset($this->myColors[$r->color_id]))
$this->myColors[$r->color_id] = true;
if(!isset($this->mySizes[$r->size_id]))
$this->mySizes[$r->size_id] = true;
if(!is_array($this->myQuantityPricing[$r->qtyrange_id]))
$this->myQuantityPricing[$r->qtyrange_id] = array();
if(!is_array($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id] = array();
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id][$r->size_id] = &$r;
}
$this->myColors = array_keys($this->myColors);
$this->mySizes = array_keys($this->mySizes);
}
}
}
$start_time = DFStdLib::exec_time();
$pmatrix = new ApparelQuote_ProductPricingMatrix_TestCase(19);
$ranges = $pmatrix->ranges();
$end_time = DFStdLib::exec_time();
$duration = $end_time - $start_time;
echo "Output generation duration was: $duration sec";
fastcgi_finish_request();
$fastcgi_finish_request_duration = DFStdLib::exec_time() - $end_time;
DFSkel::log(DFSkel::LOG_INFO,"Output generation duration was: $duration sec; fastcgi_finish_request Duration was: $fastcgi_finish_request_duration sec");
Upon continued debugging I have narrowed down to the following lines from the above:
if(!is_array($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id] = array();
These statements are building an in-memory array structure of all the data loaded from MySQL. If I comment these out, then fastcgi_finish_request takes roughly 0.0001 seconds to run. If I do not comment them out, then fastcgi_finish_request takes 7+ seconds to run.
It's actually the function call to is_array that's the issue here
Changing to:
if(!isset($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
Resolves the problem. Why is this?

issue with stream_select() in PHP

I am using stream_select() but it returns 0 number of descriptors after few seconds and my function while there is still data to be read.
An unusual thing though is that if you set the time out as 0 then I always get the number of descriptors as zero.
$num = stream_select($read, $w, $e, 0);
stream_select() must be used in a loop
The stream_select() function basically just polls the stream selectors you provided in the first three arguments, which means it will wait until one of the following events occur:
some data arrives
or reaches timeout (set with $tv_sec and $tv_usec) without getting any data.
So recieving 0 as a return value is perfectly normal, it means there was no new data in the current polling cycle.
I'd suggest to put the function in a loop something like this:
$EOF = false;
do {
$tmp = null;
$ready = stream_select($read, $write, $excl, 0, 50000);
if ($ready === false ) {
// something went wrong!!
break;
} elseif ($ready > 0) {
foreach($read as $r) {
$tmp .= stream_get_contents($r);
if (feof($r)) $EOF = true;
}
if (!empty($tmp)) {
//
// DO SOMETHING WITH DATA
//
continue;
}
} else {
// No data in the current cycle
}
} while(!$EOF);
Please note that in this example, the script totally ignores everything aside from the input stream. Also, the third section of the "if" statement is completely optional.
Does it return the number 0 or a FALSE boolean? FALSE means there was some error but zero could be just because of timeout or nothing interesting has happen with the streams and you should do a new select etc.
I would guess this could happen with a zero timeout as it will check and return immediately. Also if you read the PHP manual about stream-select you will see this warning about using zero timeout:
Using a timeout value of 0 allows you to instantaneously poll the status of the streams, however, it is NOT a good idea to use a 0 timeout value in a loop as it will cause your script to consume too much CPU time.
If this is a TCP stream and you want to check for connection close you should check the return value from fread etc to determine if the other peer has closed the conneciton. About the read streams array argument:
The streams listed in the read array will be watched to see if characters become available for reading (more precisely, to see if a read will not block - in particular, a stream resource is also ready on end-of-file, in which case an fread() will return a zero length string).
http://www.php.net/stream_select
Due to a limitation in the current Zend Engine it is not possible to
pass a constant modifier like NULL directly as a parameter to a
function which expects this parameter to be passed by reference.
Instead use a temporary variable or an expression with the leftmost
member being a temporary variable:
<?php $e = NULL; stream_select($r, $w, $e, 0); ?>
I have a similar issue which is caused by the underlying socket timeout.
Eg. I create some streams
$streams = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
Then fork, and use a block such as the following
stream_set_blocking($pipes[1], 1);
stream_set_blocking($pipes[2], 1);
$pipesToRead = array($pipes[1], $pipes[2]);
while (!feof($pipesToRead[0]) || !feof($pipesToRead[1])) {
$reads = $pipesToRead;
$writes = null;
$excepts = $pipesToRead;
$tSec = null;
stream_select($reads, $writes, $excepts, $tSec);
// while it's generating any kind of output, duplicate it wherever it
// needs to go
foreach ($reads as &$read) {
$chunk = fread($read, 8192);
foreach ($streams as &$stream)
fwrite($stream, $chunk);
}
}
Glossing over what other things might be wrong there, my $tSec argument to stream_select is ignored, and the "stream" will timeout after 60 seconds of inactivity and produce an EOF.
If I add the following after creating the streams
stream_set_timeout($streams[0], 999);
stream_set_timeout($streams[1], 999);
Then I get the result I desire, even if there's no activity on the underlying stream for longer than 60 seconds.
I feel that this might be a bug, because I don't want that EOF after 60 seconds of inactivity on the underlying stream, and I don't want to plug in some arbitrarily large value to avoid hitting the timeout if my processes are idle for some time.
In addition, even if the 60 second timeout remains, I think it should just timeout on my stream_select() call and my loop should be able to continue.

PHP microtime strange behavior

I was looking at execution time of some functions, but i have found that microtime is getting wrong, in one microtime()
implementation №1 always first time is always getting more then second microtime() executing, when i testing one function and saw that one case is faster then another, but after place replace (2nd function to 1st place), it getting slower anyway, even if it was 3x faster...
function dotimes($times,$eval,$data=false) {for(;--$times;) eval($eval);}
$start = microtime(true);
dotimes(1000,'$i = $i?$times/2:1;');
printf(": executed : %f\n",microtime(true)-$start);
$start = microtime(true);
dotimes(1000,'$i = $i?$times/2:1;');
printf(": executed : %f\n",microtime(true)-$start);
// 1st case is always slower...
implementation №2 iv made sometimes before microtime() as static data storage, but in that case the time of execute is always second time is slower then first (oposite to implementation №1)
function get_execution_time()
{
static $microtime_start = null;
return $microtime_start === null ? $microtime_start = microtime(true) : microtime(true) - $microtime_start;
}
function dotimes($times,$eval,$data=false) {for(;--$times;) eval($eval);}
get_execution_time();
dotimes(1000,'$i = $i?$times/2:1;');
printf(": executed : %f\n<br>",get_execution_time());
get_execution_time();
dotimes(1000,'$i = $i?$times/2:1;');
printf(": executed : %f\n<br>",get_execution_time());
//now 2nd case is faster..
Can somebody tell me what is going up? Why these microtimes in one case 1st always slower, and throught static storage 2nd execute is slow down, WHY?
ps if someone need tiny mt function here is my FIXED AND WORKING CORRECT:
function get_mt() {static $mt; return $mt ? microtime(true)-$mt.$mt=null : $mt=microtime(true);}
attached :
function get_mt() {static $mt; return $mt?microtime(true)-$mt:$mt=microtime(true);}
function dotimes($times,$eval,$data=false) {for(;--$times;) eval($eval);}
$start = microtime(true);
get_mt();
dotimes(10000,'$i = $i?$times/2:1;');
printf(":clean executed : %f\n<br>",microtime(true)-$start);
printf(":static executed : %f\n<br>",get_mt());
$start = microtime(true);
get_mt();
dotimes(10000,'$i = $i?$times/2:1;');
printf(":clean executed : %f\n<br>",microtime(true)-$start);
printf(":static executed : %f\n<br>",get_mt());
So far, I see that implementation №1 is correct. No clue what you tried in your second implementation.
The advice here - never test two cases in the same script. Run them separately a few times and then find the average time. PHP allocates memory when it needs and this is a slow operation. The second case may reuse already allocated memory and skip this operation and you get wrong results.
static makes a variable semi global within that function retative to function name.
I would say the delay goes in the fact that the static array needs to be checked for the previous value of the static variable.
extra work == delay

Can't find the memory leak in this snippet

using PHP Version 5.3.5
I am going insane.
This piece of code is giving me hard time. After I refresh the page on Apache a few times, I get weird results. I think I have a memory leak here, but I can't find out why.
Please help !
<?php
function ost($active_sub_time,$arr_subscription_values)
{
$result=0;
while($active_sub_time>=12)
{
$active_sub_time-=12;
$result+=($arr_subscription_values['COST_12']);
}
while($active_sub_time>=6)
{
$active_sub_time-=6;
$result+=($arr_subscription_values['COST_6']);
}
while($active_sub_time>=3)
{
$active_sub_time-=3;
$result+=($arr_subscription_values['COST_3']);
}
while($active_sub_time>=1)
{
$active_sub_time-=1;
$result+=($arr_subscription_values['COST_1']);
}
if($active_sub_time>0)
$result+=($active_sub_time)*($arr_subscription_values['COST_1']);
if (!is_numeric($result))
{
echo"<br> Bug occurred";break; // print other values if necessary
}
return $result;
}
$datetime1 = date_create('2009-01-11');
$datetime2 = date_create('2001-11-09');
$interval = date_diff($datetime1, $datetime2);
$num_of_months = ($interval->y)*12 + ($interval->m) + ($interval->d)/(cal_days_in_month(CAL_GREGORIAN, $datetime2->format("m"), $datetime2->format("Y")));
$v = array('COST_1'=>'3.99','COST_3'=>'9.99','COST_6'=>'15.99','COST_12'=>'24.99');
echo "OPT value for $num_of_months months=".ost($num_of_months,$v);
?>
I do get this result at first:
OPT value for 86.066666666667 months=183.176
But after a few refreshes I get this :
OPT value for G.GMMMMMMMMMMMN months=183.176
Does anyone know why this is ?
Thanks
Cannot reproduce, I used your code exactly, and executed it multiple times. It displays the same result.
There may be an issue with your server, or mashing refresh over and over is causing some kind of problem or memory limit.
Check your php.ini and see if your memory limit is set too low, or max requests?

Categories