Random occurrence of "Cannot redefine..." error - php

PHP 5.6, Windows Server 2016, IIS 10
The error is familiar to anyone in PHP:
PHP Fatal error: Cannot redeclare mainContent() (previously declared in [the controller file]:12) in [some included file] on line 29
Here's the thing: this error just appears. A program that has been working for days and hasn't been touched just starts throwing the error. When I restart IIS the error goes away and everything goes back to working normally.
This is similar to this bug: https://bugs.php.net/bug.php?id=30075
So here's what it's not:
The function isn't declared twice, anywhere in the program. The function name in question "mainContent" is reserved and used once and only once in any program.
Every include/require is include_once or require_once, no exceptions, so it's not a double-include.
I am sure of these two facts because I'm the only developer, so there's no one else to make changes, let alone break the code without me knowing.
When I search for a solution, all I find whether I'm on Google / Bing / Yahoo / stackoverflow / reddit is the usual explanations of double-include or declared the function twice. The error just shows up on an untouched program that's been working for days without this error, then goes away with an IIS restart. It's not in the code!
I can't be the only person who's ever encountered this problem, but I can't find a solution.
(I intend to upgrade the site to PHP7, but it's not a 1 <=> 1 transition and the client's daily business tolerates no down-time so I'm stuck here for a while longer.)

Here's a simple example to reproduce the problem you have reported:
<?php
function foo(int $a) {
echo $a;
echo "\n";
}
function bar(int $b) {
echo $b;
echo "\n";
}
echo "I'm running. gonna redeclare\n";
function foo(int $x) {
print "i'm the redeclared foo\n";
}
foo(23);
echo "finito\n";
You can save it to a file named "test.php" and execute it with
php "c:\path\to\test.php"
The error message is telling you that you a function with the same name has been declared twice.
Mind you, if this is a web app, then the concept of "running for days" is not exactly correct because each request to a specific PHP script in a web application is a new execution of the script in a sort of clean-slate environment. Some state may be shared such as the Session, and out of band data like files and database objects, but that's about it.
Unless it's some kind of long-running script, then the number of days is not relevant.
It's entirely possible that this code-path simply only gets traversed in some specific conditions.
Without any additional context, this is the best I can offer.

Related

PHP clean_all_processes() giving 500 internal error, but still outputs

So my PHP file is meant to check if a variable is null, if so than echo and output, and stop there
Here is that code:
if(is_null($ip)){
echo "IP is not valid";
clean_all_processes();
}
So when I try to test this script using the insomnia rest client it outputs the "IP is not valid" but also gives a "500 internal server error"
In my error_log file it spits out this every time
Uncaught Error: Call to undefined function clean_all_processes()
Note: I am using php 7.3
There is no such function called clean_all_processes() in PHP. The answer you linked to used it as an example name of a function you could call.
If you want a hard stop of your script use die(). This is not recommended! You should structure your code in such a way that you should almost never need to use this approach.
There is no way to break out of if statement, because such thing makes no sense. An if statement is already a condition. You either execute the code or don't.

How to stop PHP code execution?

Is there a way to immediately stop PHP code execution?
I am aware of exit but it clearly states:
Terminates execution of the script. Shutdown functions and object destructors will always be executed even if exit is called.
So what I want to achieve is to stop the PHP code execution exactly when I call exit or whatever.
Any help?
Edit: After Jenson's answer
Trial 1:
function newExit() {
__halt_compiler();
}
echo "start";
newExit();
echo "you should not see this";
Shows Fatal error: __HALT_COMPILER() can only be used from the outermost scope in which was pretty expected.
Trial 2:
function newExit() {
include 'e.php';
}
echo "start";
newExit();
echo "you should not see this";
e.php just contains __halt_compiler();
This shows startyou should not see this
Edit: Why I want to do this?
I am working on an application that includes a proprietary library (required through virtual host config file to which I don't have access) that comes as encrypted code. Is a sort of monitoring library for security purpose. One of it's behaviours is that it registers some shutdown functions that log the instance status (it saves stats to a database)
What I want to do is to disable this logging for some specific conditions based on (remote IP)
Please see the following information from user Pekka 웃
According to the manual, destructors are executed even if the script gets terminated using die() or exit():
The destructor will be called even if script execution is stopped using exit(). Calling exit() in a destructor will prevent the remaining shutdown routines from executing.
According to this PHP: destructor vs register_shutdown_function, the destructor does not get executed when PHP's execution time limit is reached (Confirmed on Apache 2, PHP 5.2 on Windows 7).
The destructor also does not get executed when the script terminates because the memory limit was reached. (Just tested)
The destructor does get executed on fatal errors (Just tested) Update: The OP can't confirm this - there seem to be fatal errors where things are different
It does not get executed on parse errors (because the whole script won't be interpreted)
The destructor will certainly not be executed if the server process crashes or some other exception out of PHP's control occurs.
Referenced in this question
Are there any instances when the destructor in PHP is NOT called?
whats wrong with return ?
echo "you will see this";
return;
echo "you will not see this";
You can use __halt_compiler function which will Halt the compiler execution
http://www.php.net/manual/en/function.halt-compiler.php
You could try to kill the PHP process:
exec('kill -9 ' . getmypid());
Apart from the obvious die() and exit(), this also works:
<?php
echo "start";
__halt_compiler();
echo "you should not see this";
?>
I'm not sure you understand what "exit" states
Terminates execution of the script. Shutdown functions and object destructors will always be executed even if exit is called.
It's normal to do that, it must clear it's memmory of all the variables and functions you called before. Not doing this would mean your memmory would remain stuck and ocuppied in your RAM, and if this would happen several times you would need to reboot and flush your RAM in order to have any left.
or try
trigger_error('Die', E_ERROR);

ReferenceError, Function not Defined

I am very new to php and I tried to write this function. Now it seems like the function is not Defined. Nothing happens when I open the php file and if I try to use console to run it. It gives an error --
contentcheck('ex1.php','Bajestani')
ReferenceError: contentcheck is not defined
The Code is below.
<?php
if(contentcheck('ex1.php','Bajestani')===true)
echo 'Got it';
function contentcheck($filename,$phrase)
{
$content = shell_exec('C:\xampp\htdocs\docman\pdftotext '.$filename.' -');
if (strpos($content,$phrase) !== false)
{
return true;
}
else
return false;
}
if(contentcheck('ex1.php','Bajestani')===true)
echo 'Got it';
?>
Thanks In advance
You state that you try to run the function from the console.
In addition, ReferenceError: contentcheck is not defined is a Javascript error, not a PHP error.
Both of these facts lead me to the conclusion that you are trying to run the PHP code from inside the browser.
Please note that PHP code is not available from within the browser -- the function will indeed be undefined if you run it in the console, because PHP is run on the web server, not in the browser. The browser will never see your PHP functions; it simply sees the output of the PHP program (eg the HTML code, etc that is printed from by your PHP program). The PHP code itself is never seen by the browser.
It's not entirely clear what your program is supposed to be doing but what is clear is that the way you're trying to run it is not going to work. You're going to have to re-think this one completely, and possibly learn a bit more about how client/server systems work, and PHP in particular.

Selenium RC WaitForPageToLoad Hangs

I am trying to get Selenium RC up and running for doing some automated testing on my website. I am finding that I constantly want to verify that I haven't broken any features, and manual testing is starting to become tiresome.
However, I can't seem to get Selenium RC to work with WaitForPageToLoad.
I tried copying the basic example that they give in the selenium documentation, but the test always gets stuck at: $this->waitForPageToLoad("30000"); I can see that it gets that far in the window that it brings up and that the page appears to have loaded correctly (we are at a google search result page). But the test fails with a timeout.
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
/**
* Description of Test
*
* #author brian
*/
class Test extends PHPUnit_Extensions_SeleniumTestCase {
function setUp() {
$this->setBrowser("*safari");
$this->setBrowserUrl("http://www.google.com/");
}
function testMyTestCase() {
$this->open("/");
$this->type("q", "selenium rc");
$this->click("btnG");
$this->waitForPageToLoad("30000");
$this->assertTrue($this->isTextPresent("Results * for selenium rc"));
}
}
What is even more interesting is that if I refresh the page when it is waiting, everything continues on as expected. So it would appear as though the waitForPageToLoad isn't realizing that the page has already loaded.
The example in the Selenium RC documentation is obsolete. Google changed the way their home page worked quite a while ago, and it is no longer a simple HTML page. Pressing the search button is now an AJAX-type operation that sends the search request and gets back a JSON response that is processed by the JavaScript code in the page. So the page never is re-loaded, and WaitForPageToLoad() eventually times out.
There is also another possible cause of this situation that I ran into just now. According to the documentation, if you call ANY SELENIUM COMMANDS in between loading a page and calling waitForPageToLoad, then it is possible that waitForPageToLoad will hang. (If I understand it correctly, it is technically a race condition between the test script and selenium server, so it happens sometimes, not necessarily all the time).
In most cases, the page load is caused by a click event. When you have a test script like:
$this->click("/some/path");
// <<- NO SELENIUM COMMANDS HERE
$this->waitForPageToLoad("30000");
Make extra sure that no selenium commands ever accidentally get inserted into the marked area.
While this is not technically the same problem that the OP posted about, it has the same error message, and I couldn't find this information without digging around quite a bit. Hopefully this is easier to find for other people in the future.
I have observed same problem many times. Hence I did not use this command when user is not navigating away from current page. It hangs at times and using IsElementPresent in while loop and exit after it return true.
An alernative to "WaitForPageToLoad()" Is to wait for an element to be present.
$SECONDS = 360;
for ($second = 0; ; $second++) {
if ($second >= $SECONDS) $this->fail("TIMEOUT");
try {
if ($this->isElementPresent("edit-submit")) break;
} catch (Exception $e) {}
sleep(1);
}
This code will loop for 360 seconds, checking if the value (edit-submit) is present each second. ("sleep(1)"). It essentially will achieve the same result as WaitForPageToLoad, but you can specify an absolute target.

Fatal error php

Is there a way to make the code continue (not exit) when you get a fatal error in PHP?
For example I get a timeout fatal error and I want whenever it happens to skip this task and the continue with others.
In this case the script exits.
There is a hack using output buffering that will let you log certain fatal errors, but there's no way to continue a script after a fatal error occurs - that's what makes it fatal!
If your script is timing out you can use set_time_limit() to give it more time to execute.
"Fatal Error", as it's name indicates, is Fatal : it stop the execution of the script / program.
If you are using PHP to generate web pages and get a Fatal error related to max_execution_time which, by defaults, equals 30 seconds, you are certainly doing something that really takes too mych time : users won't probably wait for so long to get the page.
If you are using PHP to do some heavy calculations, not in a webpage (but via CLI, or a cron, or stuff like that), you can set another (greater) value for max_execution_time.
You have two ways of doing that :
First is to modify php.ini, to set this value (it's already in the file ; just edit the property's value). Problem is it'll modify it also for the web server, which is bad (this is a security measure, after all).
Better way is to create a copy of php.ini, called, for instance, phpcli.ini, and modify this file. Then, use it when invoking php :
php -c phpcli.ini myscript.php
This'll work great if you have many properties you need to configure for CLI execution. (Like memory_limit, which often has to be set to a higher value for long-running batches)
The other way is to define a different value for max_execution_time when you invoke php, like this :
php -d max_execution_time=60 myscript.php
This is great if you launch this via the crontab, for instance.
It depends on the exact error type. You can catch errors by creating your own error handler. See the documentation on set_error_handler(), but not all types of errors can be caught. Look at the timeout error you get and see what type it is. If it is one of E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR or E_COMPILE_WARNING then you cannot catch it with an error handler. If it another type then you can. Catch it with the error handler and simply return.
If you have a suitable PHP version (PHP>=5.2 for error_get_last) you can try the technique described here which uses register_shutdown_function and error_get_last.
This won't allow you to "continue" when you get a fatal error, but it at least allows you to log the error (and perhaps send a warning email) before displaying a custom error page to the user.
It works something like this:
function fatalErrorHandler()
{
$lastError = error_get_last();
if (isset($lastError["type"]) && $lastError["type"]==E_ERROR) {
// do something with the fatal error
}
}
...
register_shutdown_function('fatalErrorHandler');
A few points:
you can use ob_clean() to remove any content that was generated prior to the fatal error.
it's a really bad idea to do anything to intensive in the shutdown handler, this technique is about graceful failure rather than recovery.
whatever you do, don't try to log the error to a database ... what if it was a database timeout that caused the fatal error?
for some reason I've had problems getting this technique to work 100% of the time when developing in Windows using WAMP.
The most simple answer I can give you is this function: http://php.net/manual/en/function.pcntl-fork.php
In more detail, what you can do is:
Fork the part of the process you think might or might not cause a fatal error (i.e. the bulk of your code)
The script that forks the process should be a very simple script.
For example this is something that I would do with a job queue that I have:
<?php
// ... load stuff regarding the job queue
while ($job = $queue->getJob()) {
$pid = pcntl_fork();
switch ($pid) {
case -1:
echo "Fork failed";
break;
case 0:
// do your stuff here
echo "Child finished working";
break;
default:
echo "Waiting for child...";
pcntl_wait($status);
// check the status using other pcntl* functions if you want
break;
}
}
Is there a way then to limit the execution time of an function but not all script?
For example
function blabla()
{
return "yes";
}
to make it so that if it is not executed in 25 seconds to return no;

Categories