Cannot send session cookie - headers already sent [duplicate] - php

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Headers already sent by PHP
Below is a simple example of my PHP code which (I hope so) is self explanatory. What I try to do is to update the session variable. But the output of the script is as follows:
Warning: session_start()
[function.session-start]: Cannot send
session cookie - headers already sent
by (output started at
/Library/WebServer/Documents/facebook/test.php:8)
in
/Library/WebServer/Documents/facebook/test.php
on line 11
The warning is caused by the echo statements in line 8 and 9, of course. Is there any simple solution to stop this warning.
Thanks for any pointers, Andrej
<?php
session_start();
$_SESSION['percent'] = 0;
$iterations = 50;
for ($i = 0; $i <= iterations; $i++) {
$percent = ($i / $iterations) * 100;
echo "Hello World!";
echo "<br />";
// update session variable
session_start();
$_SESSION['percent'] = number_format($percent, 0, '', '');
session_commit();
}
?>
The only solution that works (i.e. updates the session variable) for me is:
<?php
ob_start();
session_start();
$_SESSION['percent'] = 0;
$iterations = 50;
for ($i = 0; $i <= 50; $i++) {
$percent = ($i / $iterations) * 100;
echo "Hello World!";
echo "<br />";
// update session variable
session_start();
$_SESSION['percent'] = number_format($percent, 0, '', '');
session_commit();
}
ob_flush();
?>
It's ugly, while it buffers the output first...

Remove the session_start() from inside the for loop.
Put the session_commit() outside the for loop at the very end.
Both these functions should only be called once in a script.

It's not possible to set cookies (or send any other headers) after output is started. You could add ob_start() at line 1 to buffer the output.
The right solution is to separate logic from the output. Check out e.g.
http://www.paragoncorporation.com/ArticleDetail.aspx?ArticleID=21

If you don't have any previeus output before the session-start() statement,then try to resave your .php file as an ansi-file or as utf-8 without BOM file.
that's bc in some cases the editor itself writes things as an output in the file.
It worked for me

You have to execute the session_start() function only once. So just drop the one within the loop.
Also you don't have to do the session_commit() manually, in most cases PHP handles this for you automatically.

As the others have stated, the cause of the error is the second session_start() you are using. However, the actual reason it's throwing an error is because you are trying to set a header after you've already sent output. Since the session_start() function sets the session cookie, it tried to set the cookie header, which is after you already echo content.

Related

Assign PHP variable only once throughout application

I have a php file(ext.php) which has the PHP code as:
<?php
$i = 0;
while($i < 1000){
echo $i;
ob_flush();
flush();
sleep(1);
$i++;
}
?>
I have to include ext.php into my application's index.php, my consideration is:
$i should be assigned with 0 only once through application
You mean once in execution or one even if you have multiple requests? You can use include_once.php for execution problem, or save $i in session for multiple requests problem.

is each session call is separate call to server

Keeping in mind of server load, I want to know whether each call to session is a separate call to server which increases server load?
Let me explain it little bit. Suppose in each php page, I have to set 10 session data and have to call 10 session data also like this:
$_SESSION['a']=1;
$_SESSION['b']=2;
$_SESSION['c']=3;
$_SESSION['d']=4;
$_SESSION['e']=5;
$_SESSION['f']=6;
$_SESSION['g']=7;
$_SESSION['h']=8;
$_SESSION['i']=9;
$_SESSION['j']=10;
echo $_SESSION['a'];
echo $_SESSION['b'];
echo $_SESSION['c'];
echo $_SESSION['d'];
echo $_SESSION['e'];
echo $_SESSION['f'];
echo $_SESSION['g'];
echo $_SESSION['h'];
echo $_SESSION['i'];
echo $_SESSION['j'];
setting of above 10 sessions and outputting the same, will these be 20 separate calls to server or by session_start(), whole session data is loaded at once during page loading?
Also want to know how to store multidimensional associative array in session? Suppose I want to set the above 10 session data like this:
$_SESSION['mydata']=array(
a=>1,
b=>2,
c=>3,
d=>4,
e=>5,
f=>6,
g=>7,
h=>8,
i=>9,
j=>10
)
echo $_SESSION['mydata']['a'];
By the above example I can reduce server loads if each session call is separate call to server.
Anyone clear me what's going on when we set and get session data?
Here is the breakdown of a session
session_start(); either creates a session file on the hard drive or accesses one if it is already there. It is a serialized array
This array gets loaded into memory and is manipulated within memory until the script finishes executing or you can force it to re-write the file with session_write_close()
You can add/remove as much data as you wish after you have started the session because it is no different than manipulating an array.
The heavy lifting is done at session_start and session_write_close because that is when PHP actually has to access the hard drive
In theory each user can have a 4GB session file on a FAT32 server, or larger on NTFS server, but I am sure you can imagine the horrendous performance issues that would arise.
The whole execution of your script is done in one request. By setting $_SESSION['foo']='bar' and $_SESSION['baz']='biz' you don't set two different sessions but rather two session variables.
So the whole session is loaded on script start, not page load (that's a client-side term).
It's all being done with cookies.
EDIT, to answer your comment:
As others mentioned (see Mark Baker's comment) the session is loaded once, right before the script kicks off, and stored once after script end (unless you explicitly call session_write_close())
Sure, size matters. Apparently, the bigger the session the longer it will take to be loaded/stored. But that would be the last thing you would bother to optimize.
Benchmark for session
For $_SESSION['mydata']['key'] = 'value' :
session_start();
$time_begin = microtime(true);
$mem_start = memory_get_usage();
for ($i=0; $i < 100000; $i++) {
$_SESSION['mydata']["a$i"] = $i;
}
foreach ($_SESSION['mydata'] as $key => $value) {
$r = $value;
}
$mem_end = memory_get_usage();
$time_end = microtime(true);
echo "Time :";
echo $time_end - $time_begin;
echo "<br>";
echo "Memory :";
echo $mem_end - $mem_start;
My result about $_SESSION['mydata']['key']:
Time :0.57849311828613
Memory :464
For $_SESSION['key'] = 'value' :
<?php
session_start();
$time_begin = microtime(true);
$mem_start = memory_get_usage();
for ($i=0; $i < 100000; $i++) {
$_SESSION["a$i"] = $i;
}
for ($i=0; $i < 100000; $i++) {
$r = $_SESSION["a$i"];
}
$mem_end = memory_get_usage();
$time_end = microtime(true);
echo "Time :";
echo $time_end - $time_begin;
echo "<br>";
echo "Memory :";
echo $mem_end - $mem_start;
My result about $_SESSION['mydata']:
Time :0.47217416763306
Memory :176
EDITED : In the first PHP Script memory spented by the mydata array and the other mydata's keys.So, second way is greater again.
So , using $_SESSION['key'] = 'value' is greater than $_SESSION['my']['key'] = 'value'.
This can be a reason that when you want to set a value to $_SESSION['my']['key'], php should get $_SESSION['my'] and after that it can be create new var. in the $_SESSION['my']['key']

Outputting exec() ping result progressively

I'm trying to write a function that pings a few hundred addresses and returns their values (milliseconds). So far I've achieved the initial idea which is to ping and get the result but the problem arises when using the same code for hundreds of addresses, the PHP page stalls until it either times out or reaches the last ping command.
I would be glad if I could get some suggestions to output the results progressively, here is my current code:
<?php
// "for" loop added according to suggestion for browser compatibility (IE, FF, CHR, OPR, SFR)
for($i = 0; $i < 5000; $i++)
{
echo ' ';
}
function GetPing($ip = NULL) {
// Returns the client ping if no address has been passed to the function
if(empty($ip)) {
$ip = $_SERVER['REMOTE_ADDR'];
}
// Check which OS is being run by the client
if(getenv('OS') == 'Windows_NT') {
//echo '<b>Detected local system:</b> Windows NT/2000/XP/2003/2008/Vista/7<p>';
$exec = exec("ping -n 1 -l 32 -i 128 " . $ip);
return end(explode(' ', $exec));
}
else {
//echo '<b>Detected local system:</b> Linux/Unix<p>';
$exec = exec("ping -c 1 -s 32 -t 128 " . $ip);
$array = explode('/', end(explode('=', $exec )));
return ceil($array[1]) . 'ms';
}
// ob_flush and flush added according to suggestion for buffer output
ob_flush();
flush();
}
// Added to test 20 sequential outputs
for($count = 0; $count < 20; $count++)
echo GetPing('8.8.8.8') . '<div>';
?>
After some feedback, I've added a for loop as well as ob_flush() and flush() to my script and I've also set output_buffering to 0 in php.ini. It seems to work for most browsers that I tested so far (IE8, Firefox 12, Chrome 19, Opera 11, Safari 5). It seems the current code is now working as intended but any suggestion to improve on it is immensely appreciated.
Thank you for your feedback.
this is just a guess; I've written years ago a very wobbly chat script that used output buffering as well (and fetching new messages in while(true) loop) ..
While doing this I've encountered the same problems that sometimes the script stalled (blank screen), sometimes it took a while until the characters appeared and additionally this was also browser specific.
Here are the relevant code snippets I've added to the script to have it work with IE6 and FF2 (as I said, years ago ...)
<?php
// End output buffering
ob_end_flush();
// IE and Safari Workaround
// They will only display the webpage if it's completely loaded or
// at least 5000 bytes have been "printed".
for($i=0;$i<5000;$i++)
{
echo ' ';
}
while( ... )
{
echo 'Message';
ob_flush();
flush();
}
?>
It worked for me, so maybe you could give it a try as well. (Altough I have no idea how modern browsers and server infrastrucutre will behave to this).
I think what you may be looking for is progressively running and outputting the script, rather than asynchronous functions.
See Is there a way to make PHP progressively output as the script executes?

File reading, searching and looping problems

So i've been trying to write this little piece of code to read a file (status.txt), search it for 1 of 4 keywords and loop until either time runs out (5 minutes) or it finds one of the words. I've already written a few simple php scripts to write the words to a txt file, but I can't seem to get this part to work. It either doesn't clear the file in the beginning or seems to hang and never picks up the changes. Any advice would be hugely helpful.
<?php
//Variables
$stringG = "green";
$stringR = "red";
$stringB = "blue";
$stringO = "orange";
$clear = "";
$statusFile = "status.txt";
//erase file
$fh = fopen($statusFile, 'w'); //clear the file with "clear"
fwrite($fh, $clear);
fclose($fh);
//Insert LOOP
$counter = 0;
while ( $counter <= 10 ) {
//echo "loop begun";
// Read THE FILE
$fh = fopen($statusFile, 'r');
$data = fread($fh, filesize($statusFile));
fclose($fh);
//process the file
if(stristr($data,$stringG)) {
echo "Green!";
$counter = $counter + 30; //stop if triggered
}
elseif (stristr($data,$stringR)) {
echo "Red";
$counter = $counter + 30; //stop if triggered
}
elseif (stristr($data,$stringB)) {
echo "Blue";
$counter = $counter + 30; //stop if triggered
}
elseif (stristr($data,$stringO)) {
echo "Orange";
$counter = $counter + 30; //stop if triggered
}
else {
//increment loop counter
$counter = $counter + 1;
//Insert pause
sleep(10);
}
}
?>
You should open the file before your read loop, and close it after the loop. As in :
open the file
loop through the lines in the file
close the file
Also, if you clear the file before you read it, isn't it going to be empty every time?
Well, first of all, you don't need to "clear" the file this way... The "w" option in fopen will already do that for you.
Also, I wouldn't try to read the whole file at once, because, if it's very large, that won't work without intense memory usage.
What you should do is read the file sequentially, which means you always read a fixed amount of bytes and look for the keywords. To avoid losing keywords which are cut in half by your reading mechanism, you could make your reads overlay a bit (the length of your longest keyword-1), to solve that problem.
Then you should modify your while loop so that it also checks if you are at the end of the file ( while(!feof($fh)) ).
PS: It has been mentioned that you clear your file before reading it. What I understood is that your file gets a lot of input really fast, so you expect it to already have content again when you reopen it. If that's not the case, you really need to rethink your logic ;)
PPS: You don't need to abort your while loop by incrementing your counter variable past the boundaries you define. You can also use the break-keyword.
You haven't included the code which deletes the file in the while loop, so it only clears the file once. Also, I'd use unlink($statusFile); to delete the file.
You should rather use for cycle. And to your problem - you clear the file, then get the data from it. Try dumping this $data, you'll end up with string(0) "" for sure. First, save the data, then clear the file.
Edit: If you are changing the file in the loop itself in another thread, there's another problem. You should look after anatomic file stream. For example, you can use Nette SafeStream class.

In PHP, is there any harm in running session_start() multiple times?

Presumably there's some tiny performance hit, but beyond that?
As of PHP 4.3.3, calling session_start() while the session has already been started will result in an E_NOTICE warning. The second call to session_start() will simply be ignored.You could check if the session has been started first or not with:
if (session_id() == "")
session_start();
From the docs:
As of PHP 4.3.3, calling session_start() after the session was previously started will result in an error of level E_NOTICE. Also, the second session start will simply be ignored.
So no, it won't "cause harm", but it'll throw an error. And the fact that it's happening is probably an indicator that you're doing something incorrectly, and might need to re-think how your code is laid out.
Calling session_start(); can harm the performance of your application.
The following code will trigger an E_NOTICE, but won't harm that much performance wise
<?php
session_start();
session_start();
?>
But calling the following will harm the performance!
But it's still useful. If you have a script that takes like 3 minutes to run and is called with XHR (js).
In this case it's useful to use the session_write_close. otherwise the request to the server is blocked until the sessions are released. It could happen that you want to use the sessions at the start of the script and at the end of the script.
<?php
session_start();
session_write_close();
session_start();
?>
But, when you call the session_start(); all information is deserialized, and when you call session_write_closed() it's serialized.
So if you have a lot of data it can be really slow!
The following test shows how much impact it has.
1.0130980014801 sesion_start + close with empty session
1.0028710365295 normal loop without session
12.808688879013 a lot data in the session with start + close
1.0081849098206 normal loop again (useless kinda)
<?php
//start and clear first session
session_start();
session_destroy();
session_write_close();
//test one
if(true) {
//test loop one
$start = microtime(true);
for($i = 0; $i < 1000; $i++) {
session_start();
usleep(100);
session_write_close();
}
$end = microtime(true);
echo($end - $start);
//test loop 2
echo('<br />');
$start = microtime(true);
for($i = 0; $i < 1000; $i++) {
usleep(100);
}
$end = microtime(true);
echo($end - $start);
}
//fill the array with information so serialization is needed
session_start();
$_SESSION['test'] = array();
for($i = 0; $i < 10000; $i++) {
$_SESSION['test'][$i] = chr($i);
}
session_write_close();
echo('<br />');
//test two
if(true) {
//test loop one
$start = microtime(true);
for($i = 0; $i < 1000; $i++) {
session_start();
usleep(100);
session_write_close();
}
$end = microtime(true);
echo($end - $start);
//test loop 2
echo('<br />');
$start = microtime(true);
for($i = 0; $i < 1000; $i++) {
usleep(100);
}
$end = microtime(true);
echo($end - $start);
}
?>
Reading the docs for session_start, all I can see is:
As of PHP 4.3.3, calling session_start() after the session was previously started will result in an error of level E_NOTICE. Also, the second session start will simply be ignored.
So, you'll get an E_NOTICE and be ignored.
I usually put a session start statement in an include file that I require_once. But I don't think there should be an issue with multiple calls.
If it produces an error, odds are that the developers didn't intend for that particular action to occur. So yes, despite what you're shown by W3Schools, it's technically a 'bad' thing to do.
So, rather than play it safe and try to set the session on each page, why not first check to see if the session exists before you move forward?
if ( !isset($_SESSION) ) session_start();
Personally, I'd check for the existence of the session's cookie first.
If the session is already open, then it will return an error notice, and the new session will be ignored. So no harm is done, but you will have a pesky error.
But... if you are finding the need to do this then it could be a symptom that your code is not organized well. It would probably be in your benefit to see how you can keep yourself from repeating redundant tasks like starting a session.

Categories