TL;DR
Getting an error on a Linux box with Nginx / PHP-FPM stating "Failed to start the session because headers have already been sent.". Error is not occurring on Apache local machine setup
So on my local machine I have the Symfony2 app running fine. No errors are popping up. But as soon as I deploy to our Linux Server I'm getting this error when I call a certain Action within a Controller class
Failed to start the session because headers have already been sent.
In the index action I have already called
$session = $this->getRequest()->getSession();
And in another action within the same controller class I'm calling it again. The error pops up when I try a
$session->set('foo', $bar);
In my Twig I'm calling the action by a form and a button with a formaction property like so
<form id='blahblah'>
.... some fields here .....
<button type='submit' formaction='{{path('2ndAction')}}'></a>
</form>
So on my local machine, running Apache everything run fine. The Linux server is using Nginx and php-fpm and it's crashing for some reason. I checked the phpInfo() and the session auto start is set to off. Not sure if this is an Nginx/php-fpm issue or not but I thought it may be pertinent information.
Here is the Controller declaration, indexAction(), and my 2ndAction()
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use CBSi\Utils\HTTPUtils\CURLUtil;
class StartController extends Controller
{
/**
* #var CurlUtil $curlUtil
*/
private $curlUtil;
/**
* #var AccessControl $accessControl
*/
private $accessControl;
/*placeholder for request object*/
private $requestHolder;
/**
* #Route("/path/for/action/one", name="start")
* #Template()
*/
public function indexAction()
{
$session = $this->getRequest()->getSession();
$this->curlUtil = $this->get('curlUtil');
$this->requestHolder= Request::createFromGlobals();
// Some logic is done here
return $this->render('ListEngagementBundle:Start:start.html.twig');
}
/**
* #Route("/path/to/second/action", name="2ndAction")
* #Template
*/
public function 2ndAction(){
$session = $this->getRequest()->getSession();
$this-> curlUtil = $this->get('curlUtil');
$this->requestHolder= Request::createFromGlobals();
//Some logic is done here to get the data for the session variable
$bar= logic output
$session->set('foo', $bar);
return $this->redirect($this->generateUrl('start'));
}
}
If you need more info that I can provide I will :)
So I figured it out. In the 2nd action where I was calling
$session->getRequest()->getSession();
I had to change that to
$session = new Session();
$session->start();
Go figure. :P
I've get the same error. But in my case I've placed some spaces in the AppKernel.php before the < ?php
tag. So if someone else get this error, checkout if you have some spaces or tabs before in first line of each .php file which get loaded before session get initialized.
This happens to me when in some of the scripts that anticipate $this->session->start();
there is a echo statement!
Hope this can help someone else debugging the issue
I was getting this error message every time I tried to update my database schema using symfony console and when I tried to install new dependencies using composer:
[RuntimeException]
Failed to start the session because headers have already been sent by "/var
/www/html/pulsar283/src/MyService/Local/Brasil.php" at line 153.
So, I went for check the file , and, on line 152 I found a " ?> " (php close tag ).
So, to I just remove the php close tag and the error never shown again !
Related
Im using plugin, I want just to load data from my table as json, the problem is in local it's working and in the server I found this error in log :
Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at webmaster#localhost to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
my model:
<?php
class Indisponibilite extends AppModel {
var $name = 'Indisponibilite';
}
my function:
public function getIndisponible () {
$indisponibles = ClassRegistry::init('Indisponibilite')->find('all');
echo json_encode($indisponibles);
$this->layout = 'ajax';
$this->autoRender = false;
$this->render(false, "ajax");
error_reporting(0);
}
First of all: Please check the docs about JSON Views which are much more MVC and Cake-ish. For Cake 2.x check here.
Also, don’t set error_reporting. CakePHP should handle all this for you. Setting Configure::write('debug', 0) will turn off error_reporting for you.
To find your error, check the logs, turn on debug and see what’s up there.
I am working on Yii2 advanced app and I have created cron job for my need but same code inside cron works in application but not works in console cron controller.
It gives error like 'Class PDO not found'.
namespace console\controllers;
use yii\console\Controller;
class CronsController extends Controller {
public function actionIndex($id = null) {
if(isset($id)){
$command = \Yii::$app->db->createCommand("INSERT INTO table (user) VALUES (:user)");
foreach($gets as $row){
$command->bindValue(':user', $row['user']);
$command->execute();
}
}
}
first step command run
php -m | grep PDO
To see if it exists,if not exists PDO, you need install PDO extension
http://php.net/manual/en/pdo.installation.php
I'm writing a Telegram bot and I'm using the official bot API. I've got a webhook server that handles requests and sends a 200 OK response for every request.
Before the server stops, the webhook is detached so Telegram does not send updates anymore. However, whenever I turn the bot on and set the webhook URL again, Telegram starts flooding the webhook server with old updates.
Is there any way I can prevent this without requesting /getUpdates repeatedly until I reach the last update?
Here's a heavily simplified version of how my code looks like:
var http = require('http'),
unirest = require('unirest'),
token = '***';
// Attach the webhook
unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
.field('url', 'https://example.com/api/update')
.end();
process.on('exit', function() {
// Detach the webhook
unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
.field('url', '')
.end();
});
// Handle requests
var server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Thanks!');
});
server.listen(80);
Thanks in advance.
The best way is to use update_id which is a specific number that increases on every new request (i.e. update). How to implement it?
First off, let's start with the following anonymous class (using PHP7):
$lastUpdateId = new class()
{
const FILE_PATH = "last-update-id.txt";
private $value = 1;
public function __construct()
{
$this->ensureFileExists();
$this->value = filesize(self::FILE_PATH) == 0
? 0 : (int)(file_get_contents(self::FILE_PATH));
}
public function set(int $lastUpdateId)
{
$this->ensureFileExists();
file_put_contents(self::FILE_PATH, $lastUpdateId);
$this->value = $lastUpdateId;
}
public function get(): int
{
return $this->value;
}
public function isNewRequest(int $updateId): bool
{
return $updateId > $this->value;
}
private function ensureFileExists()
{
if (!file_exists(self::FILE_PATH)) {
touch(self::FILE_PATH);
}
}
};
What the class does is clear: Handling the last update_id via a plain file.
Note: The class is tried to be as short as possible. It does not provide error-checking. Use your custom implementation (e.g. use SplFileObject instead of file_{get|put}_contents() functions) instead.
Now, there are two methods of getting updates: Long Polling xor WebHooks (check Telegram bot API for more details on each methods and all JSON properties). The above code (or similar) should be used in both cases.
Note: Currently, it is impossible to use both methods at the same time.
Long Polling Method (default)
This way, you send HTTPS requests to Telegram bot API, and you'd get updates as response in a JSON-formatted object. So, the following work can be done to get new updates (API, why using offset):
$botToken = "<token>";
$updates = json_decode(file_get_contents("https://api.telegram.org/bot{$botToken}/getUpdates?offset={$lastUpdateId->get()}"), true);
// Split updates from each other in $updates
// It is considered that one sample update is stored in $update
// See the section below
parseUpdate($update);
WebHook Method (preferred)
Requiring support for HTTPS POST method from your server, the best way of getting updates at-the-moment.
Initially, you must enable WebHooks for your bot, using the following request (more details):
https://api.telegram.org/bot<token>/setWebhook?url=<file>
Replace <token> with you bot token, and <file> with the address of your file which is going to accept new requests. Again, it must be HTTPS.
OK, the last step is creating your file at the specified URL:
// The update is sent
$update = $_POST;
// See the section below
parseUpdate($update);
From now, all requests and updates your bot will be directly sent to the file.
Implementation of parseUpdate()
Its implementation is totally up to you. However, to show how to use the class above in the implementation, this is a sample and short implementation for it:
function parseUpdate($update)
{
// Validate $update, first
// Actually, you should have a validation class for it
// Here, we suppose that: $update["update_id"] !== null
if ($lastUpdateId->isNewRequest($update["update_id"])) {
$lastUpdateId->set($update["update_id"]);
// New request, go on
} else {
// Old request (or possible file error)
// You may throw exceptions here
}
}
Enjoy!
Edit: Thanks to #Amir for suggesting editions made this answer more complete and useful.
When you server starts up you can record the timestamp and then use this to compare against incoming message date values. If the date is >= the timestamp when you started...the message is ok to be processed.
I am not sure if there is a way you can tell Telegram you are only interested in new updates, their retry mechanism is a feature so that messages aren't missed...even if your bot is offline.
In the webhook mode, Telegram servers send updates every minute until receives an OK response from the webhook program.
so I recommend these steps:
Check your webhook program that you specified its address as url parameter of the setWebhook method. Call its address in a browser. It does not produce an output to view, but clears that probably there is no error in your program.
Include a command that produces a '200 OK Status' header output in your program to assure that the program sends this header to the Telegram server.
I have the same issue, then I tried to reset the default webhook with
https://api.telegram.org/bot[mybotuniqueID]/setWebhook?url=
after that, i verified the current getUpdates query were the same old updates but I sent new requests through the telegram's bot chat
https://api.telegram.org/bot[mybotuniqueID]/getUpdates
when I set up my webhook again the webhook read the same old updates. Maybe the getUpdates method is not refreshing the JSON content.
NOTE:
in my case, it was working fine until I decided to change /set privacy bot settings from botfather
The project i'm working on has a api behind a login.
I'm using behat with mink to login:
Scenario: Login
Given I am on "/login/"
And I should see "Login"
When I fill in "_username" with "test"
And I fill in "_password" with "test"
And I press "_submit"
Then I should be on "/"
This works..
However, the login session is not stored whenever i want to do the following using the WebApiContext:
Scenario: Getting the list of pages
When I send a GET request to "/api/pages.json"
Then print response
I'm using both scenarios in the same feature. My FeatureContext class looks something like this:
class FeatureContext extends MinkContext
{
public function __construct(array $parameters)
{
$context = new WebApiContext($parameters['base_url']);
$context->getBrowser()->getClient()->setCookieJar(new \Buzz\Util\CookieJar());
$this->useContext('web', $context);
}
}
I added the cookiejar idea from this issue without success.. When i print the response i just see the HTML page from the login screen..
Does anyone have any idea if i'm going at this totally the wrong way or am i somewhat in the right direction?
I am successfully using the same method. I don't think there's a standard way of doing this. As far as you understand the cookie basics you should be able to implement the solution.
In a common scenario, a client sends an authentication request to the server with some credentials, the servers validates it, starts an authenticated session and sends back a cookie with that session id. All following requests contain that id, so the server can recognise the callee. A specific header can be used instead of the cookie, or a database can be used instead of the session, but the principle is the same and you can (relatively) easily simulate it with Mink.
/**
* Start a test session, set the authenticated user and set the client's cookie.
*
* #Given /^I am signed in$/
*/
signIn()
{
session_start();
$_SESSION['user'] = 'jos';
$this->getSession()->getDriver()->setCookie(session_name(), session_id());
session_commit();
}
The above step definition (Behat 3) is the basics of it, you manually create the authenticated session and set to the client it's id. That must be also what the other example illustrates.
PHP's sessions can be problematic when you start doing more complex things and there are a couple of big underwater rocks with this solution. If you want to run assertions from both perspectives (the client and the server) you might often need to have your sessions synced. This can be done by updating the cookie before all Mink steps and reloading the session after.
/**
* #beforeStep
* #param BeforeStepScope $scope
*/
public function synchroniseClientSession(BeforeStepScope $scope)
{
// Setup session id and Xdebug cookies to synchronise / enable both.
$driver = $this->getSession()->getDriver();
// Cookie must be set for a particular domain.
if ($driver instanceof Selenium2Driver && $driver->getCurrentUrl() === 'data:,') {
$driver->visit($this->getMinkParameter('base_url'));
}
// Also enables the debugging support.
$driver->setCookie(session_name(), session_id());
$driver->setCookie('XDEBUG_SESSION', 'PHPSTORM');
}
/**
* #afterStep
* #param AfterStepScope $scope
*/
public function synchroniseServerSession(AfterStepScope $scope)
{
$driver = $this->getSession()->getDriver();
// Only browser kit driver, only initiated requests, only not repeating requests.
if (!$driver instanceof BrowserKitDriver) {
return;
} elseif (($request = $driver->getClient()->getRequest()) === null) {
return;
} elseif ($request === self::$request) {
return;
}
// Your logic for reloading the session.
self::$request = $request;
}
The biggest problem I had was the session reloading. This might be due to my framework of choice, which I doubt. The very first code snippet has session_commit(), which saves and closes the session. In theory in the following step definitions you must be able to session_id(/* session id from the cookie… */); and session_start();, but in practice that didn't work and no session data was actually loaded from the file, though the session did start. To solve this I created a custom session manager with reload() method using session save handler.
Second problem is where you cannot simply close the session without either writing it or destroying it (the support is added in PHP 5.6) on which relies the reloading itself. I reinvented the wheel with a flag for the session manager which tells it whether to write or just to close it.
:)
To use phpunit_coverage.php I need to set auto_prepend_file and auto_append_file properties in php.ini to specified files prepend.php and append.php. In both scripts cookies are checked to make sure that test is running:
if ( isset($_COOKIE['PHPUNIT_SELENIUM_TEST_ID']) &&
The problem is that this cookie is kept as localhost's cookie, not the webserver's. So when it is checked, it is not set and xdebug doesn't start.
Selenium and webserver are located on different machines, could this be the cause of this error?
Situation is displayed here:
Similar issue. I thought at first of a domain problem as the tested web site is on a vhost.
But I found out that calling $this->url('some_url') seemed to silently delete the PHPUNIT_SELENIUM_TEST_ID cookie.
My workaround was overriding the url() method in my test cases, in order to reset the cookie once url() is called.
protected function url($url =null)
{
try {
$cookie = $this->cookie()->get('PHPUNIT_SELENIUM_TEST_ID');
}
catch (Exception $e) {}
$result = parent::url($url);
if (isset($cookie)) {
$this->cookie()->add('PHPUNIT_SELENIUM_TEST_ID', $cookie)->set();
}
return $result;
}
The code coverage files are now correctly created.