I've just ported a system I wrote a few years back into PHP into a new environment that has PHP 7.1.4 instead of PHP 5.x. My programs used to work perfectly but are now throwing errors, many of which I've never seen before. I am not a fluent PHP programmer although I have programmed in a variety of languages, including Java, so I'm not new to programming by any means. I was reading a short tutorial about PHP error handling and they suggested writing an error-handling function and invoking it as follows: //Error handler function function customError($errno, $errstr, $errfile, $errline, $errcontext) { echo "<b>Error:</b> [$errno] $errstr<br>"; echo "<b>File/Line:</b> $errfile/$errline<br>"; //echo "<b>Error context:</b><br>"; //print_r($errcontext); echo "....Ending Program"; die(); } //Set error handler set_error_handler("customError",E_ALL); PHP: I did that and got this: Error: [8] Undefined index: report_layout File/Line: /storage/h13/139/1556139/public_html/SideTrekkedContributions.php/28 Code (markup): In the first line of that, am I correct in assuming that the [8] denotes the severity level of the error, specifically E_NOTICE, which is defined as "Run-time notices. The script found something that might be an error, but could also happen when running a script normally."? Or is the 8 uniquely associated with an "Undefined index" error in a world where every distinct error has a specific number associated with it, like 37 for division by zero and 412 for array index out of bounds? I think it must be the former and that there will be all kinds of errors that have the number 8 but my knowledge of PHP is sketchy so I want to be sure. Now, assuming I'm right and that 8 is the severity of the error, what should one normally do with E_NOTICE errors? Ideally, I'd like PHP not to display this message and I'd like to get rid of the message by doing whatever I need to do to prevent PHP from thinking there's anything wrong (as opposed to telling it not to show me errors below a certain severity). In this particular case, the line of code identified as the source of the error is this: switch($_POST['report_layout']) { PHP: I'm darned if I can see what's wrong with this. I never got an error of any kind about this code on the old system. But maybe the old system wanted to show me messages like this but had minor errors suppressed; I really don't know. I tried initializing that variable to null $report_layout = null; PHP: but that did NOT keep the error from appearing. I'm at a loss how to satisfy PHP that the variable has been appropriately initialized so it doesn't have to tell me that there's an undefined index. Can anyone enlighten me on the points I've raised?
Here's your list of error numbers: http://php.net/manual/en/errorfunc.constants.php [8] looks like it's a pretty generic "oops" type of result - not the severity though. Lots of people suppress error messages and do nothing about them. I'd recommend digging through your script and identifying them as you could have functions that no longer exist and will stop your script from functionining.
sarahk has already answered your other questions. Let me answer your last question. The error that you are getting clearly mentions this: Undefined index: report_layout Which means that the associative array $_POST, is not having an element with the key named as report_layout So, what you can do is, add an IF condition before that SWITCH, to check whether the array key exists! Example: if( isset( $_POST['report_layout'] ) ) { switch($_POST['report_layout']) { //...... //...... } } PHP: Hope this helps. Thank you
Thanks, Sarahk, I was pretty sure that the number 8 was the severity of the error and you've now confirmed that. As for your general point, I totally agree. I need to go through my code and improve it to prevent any of the errors from appearing in the first place. I need to get up to speed on "best practices" for PHP. I'll likely be posting specific questions as I come to problem areas and getting the advice of the experts here. I realize now why I'm seeing more PHP messages than I'm used to seeing: there was a line in my .htaccess file that the hosting service put in there automatically. They even warn you not to change it: # HTID:1177512: DO NOT REMOVE OR MODIFY THIS LINE AND THE LINES BELOW php_value display_errors 1 # DO NOT REMOVE OR MODIFY THIS LINE AND THE LINES ABOVE HTID:1177512: Code (markup): When I changed the 1 to a 0 and ran my code again, all the messages from PHP disappeared. I strongly suspect that they never used to force the display of errors on the old system but are forcing it on the new one, thus accounting for my sudden increase in messages. Naturally, this just emphasizes the need for me to improve this code so PHP doesn't even *want* to complain By the way, thanks for your prompt reply! (I'm afraid I've been side-tracked with other issues and didn't get back here until just now.)
I pretty much figured that's what was going on. The thing is that report_layout *is* defined before I get to that line of code so I'm not sure why the PHP interpreter is concluding otherwise. Here's my full code for SideTrekkedContributions.php: <!--#include file="fragments/#alfa.shtml"--> <?php include('fragments/_getThemes.php'); ?> </head> <body> <?php //Display the menu that lets the user decide which report they want include ('fragments/_SideTrekkedContributionsMenu.shtml'); //Execute the program that displays the desired report. switch($_POST['report_layout']) { case 'Format1': include('SideTrekkedContributions1.php'); break; case 'Format2': include('SideTrekkedContributions2.php'); break; case 'Format3': include('SideTrekkedContributions3.php'); break; } ?> </body> </html> PHP: And here's my code for _SideTrekkedContributionsMenu.shtml: <h2>SideTrekked Contributions</h2> <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>"> <p>You can choose from multiple layouts for the report. Please select the one you prefer, then press the Display Report button. To restore the form to its original appearance without submitting it, press the Reset button.</p> <fieldset><legend>Report Layout</legend> <input type="radio" name="report_layout" value="Format1"/>In publication order<br/> <input type="radio" name="report_layout" value="Format2"/>In order by title<br/> <input type="radio" name="report_layout" value="Format3"/>In order by contributor last name<br/> </fieldset> <p><input name="submitForm" id="submitForm" type="submit" value="Display Report" /> <input name="reset" id="reset" type="reset" value="Reset" /></p> <p><em>It may take a few seconds after you click the Display Report button to gather and format all the data. Please be patient.</em></p> </form> HTML: Given that _SideTrekkedContributionsMenu.shtml is imbedded into the code before PHP executes the switch statement, I *think* report_layout is already defined. What am I missing? What do I need to do so that PHP doesn't think report_layout is undefined?
I'd start by just doing a var_dump of $_POST before you do the switch to be sure - it could be that no value was selected and therefore the variable doesn't appear in $_POST. To get around that you need to either give report_layout a default value so that a radio button is preselected or you need to add array_key_exists before your switch.
I suppose I could force report_layout to have a value and simply let the user change that value if they didn't like the default. I'd rather not though so I think I will try the array_key_exists function. I've never come across that one before but it would let me write an if that says "if report_layout has a value, run the appropriate report, otherwise, just display the menu and await input". Apparently, the switch is being executed before the user has even chosen a report, thus prompting the complaint about the index not being defined. Thanks for the insight!
Having a default value for a multi-option selection is a must (unless we are talking about surveys and such), not a workaround. Just add DEFAULT to one of the options that you think most users would want to choose.,
Just to clarify a little bit. $_POST-values are ONLY present after a form has been submitted (a form with method="post", that is). So the form you include does not mean the $_POST['report_layout'] is defined. Nor does it mean it will be defined even if you set a default value in the form (you will have to set that in the PHP directly). A normal way to do this would be to check to see if the $_POST-value is empty, for instance like this: if (isset($_POST['submitForm'])) { //do the rest of the $_POST-processing here } PHP: Granted, this wouldn't actually check to see if there is a $_POST['report_layout'] actually set - but then again, that would be something to check like this, for instance: if (isset($_POST['submitForm'])) { if (isset($_POST['report_layout'])) { switch($_POST['report_layout']) { case 'Format1': include('SideTrekkedContributions1.php'); break; case 'Format2': include('SideTrekkedContributions2.php'); break; case 'Format3': include('SideTrekkedContributions3.php'); break; } } } PHP: That will first check to see if the form has been submitted, then check if the $_POST['report_layout'] is set. Normally you would add some error-checking, so if it is not filled out, you will present the user with an error-message explaining what needs to be done. Also, I see you're using .shtml-files - why? And your naming conventions... you are mixing camelCase (with wrong formatting - camelCase starts with a lower-case letter) with underscore naming, and you have extremely complicated names for quite a bit of code... also, the first comment doesn't seem to match the code presented, and so on.
As long as the end user is not playing with the code, it should. Second point, I've no idea why do you need two isset there - you're looking for one specific object there, not two or more. if (isset($_POST["report_layout"]) { switch ($_POST["report_layout"]) { case "Option 1": // Do something here related to Option 1; break; case "Option 2": // Do something here related to Option 2; break; case "Option 3": // Do something here related to Option 3; break; case "Option 4": // Do something here related to Option 4; break; case "Option 1": // Do something here related to Option 1; break; default: // None of the option values have been found. Throw an error? } } PHP:
Much of this debate comes down to the old idea that you should never actually use the $_POST or $_GET values directly. Your values should be moved into variables, sanitized, defaults checked and then used. The PHP code that does the logical work should also be before the <head> tag with only display variables being worked lower down. Following that then leads you into just doing MVC which can be done on even the smallest "from scratch" site - but all of that is well outside the scope of the OP's question.
Granted, in this specific instance, checking for one isset() is enough. Most forms, however, will have more than one input, and hence, checking to see if the form is actually submitted before doing anything else, is usually good practice.
As a general rule, you should never assume something is set. A simple ternary will do the job isset($_POST['index']) ? $_POST['index''] : '' PHP: Also no need to nest if statements. Following my rule of never assuming something is set I would always check that the form has been properly submitting before checking for anything else. if (isset($_POST['submit']) && isset($_POST['index'])) { } if (isset($_POST['submit'], $_POST['index'])) { } PHP: A simple var_dump($_POST); PHP: after submit will show you what is being set, if nothing, then you need to double check you're actually doing a post request you can do var_dump($_SERVER["REQUEST_METHOD"]); PHP:
If you're using modern PHP, you can just do: $index = $_POST['index'] ?? ''; PHP: No need to use isset() or anything - if the index is set, it will exist, and be used, if not, empty.
Sorry for the delay in responding; I've been playing with my PHP code learning things by trial and error when I couldn't find them in the manual. You've raised some excellent points. I had only a bare working knowledge of PHP when I first wrote this code 4 or 5 years and haven't touched it since so I'd forgotten a bunch of things including the fact that report_layout wouldn't have a value if none of the report types were chosen on the form; for some reason, I thought it always had some kind of value, even if it was just blank or null. That is why I was perplexed about the error I was getting. Once I remembered that $_POST only contains values that were selected or typed by the user, I rewrote the code to check everything that came back in $_POST and to put it in its own work variable; if any given value wasn't in $_POST, I set an arbitrary value. I tested via array_key_exists(). For example: (array_key_exists('proposer', $_POST)) ? $proposer = trim($_POST['proposer']) : $proposer = ""; //This is the Proposer text field. PHP: Is there any reason why that is better or worse than isset() (or any of the other possible approaches)? I also hadn't realized that the switch statement would be executed immediately after the form had been shown the user, before he/she had had a chance to choose a report format. I simply put an if around the whole switch statement so it wouldn't be executed until report_layout had a value, which would only happen after pressing Submit: //If the user has selected a report, execute the program that displays the desired report. if (array_key_exists('report_layout', $_POST)) { switch($_POST['report_layout']) { case 'Format1': include('SideTrekkedContributions1.php'); break; case 'Format2': include('SideTrekkedContributions2.php'); break; case 'Format3': include('SideTrekkedContributions3.php'); break; } //end switch } //end if PHP: Would you agree that this is a reasonable way to handle things or could I be doing better?
That all looks good. The only thing I'd change is $prosper = (array_key_exists('proposer', $_POST)) ? trim($_POST['proposer']) : ""; PHP: But there's also @PoPSiCLe's way which I haven't yet tried $prosper = $_POST['prosper'] ?? ''; PHP:
AKE only checks if a key exists and doesn't care about the value, where as isset will return false if it exists but is a null value... so in this case you are fine to use AKE.
And I would say that the new PHP 7-way is cleaner all around. But yes, the method you're using is perfectly fine.
This is small program done using your error handler and it's working fine. <?php // error handler function function myErrorHandler($errno, $errstr, $errfile, $errline) { echo "<b>Error:</b> [$errno] $errstr<br>"; echo "<b>File/Line:</b> $errfile/$errline<br>"; echo "....Ending Program"; die(); } // function to test the error handling function scale_by_log($vect, $scale) { if (!is_numeric($scale) || $scale <= 0) { trigger_error("log(x) for x <= 0 is undefined, you used: scale = $scale", E_USER_ERROR); } if (!is_array($vect)) { trigger_error("Incorrect input vector, array of values expected", E_USER_WARNING); return null; } $temp = array(); foreach($vect as $pos => $value) { if (!is_numeric($value)) { trigger_error("Value at position $pos is not a number, using 0 (zero)", E_USER_NOTICE); $value = 0; } $temp[$pos] = log($scale) * $value; } return $temp; } // set to the user defined error handler $old_error_handler = set_error_handler("myErrorHandler"); // trigger some errors, first define a mixed array with a non-numeric item echo "vector a\n"; $a = array(2, 3, "foo", 5.5, 43.3, 21.11); print_r($a); // now generate second array echo "----\nvector b - a notice (b = log(PI) * a)\n"; /* Value at position $pos is not a number, using 0 (zero) */ $b = scale_by_log($a, M_PI); print_r($b); // this is trouble, we pass a string instead of an array echo "----\nvector c - a warning\n"; /* Incorrect input vector, array of values expected */ $c = scale_by_log("not array", 2.3); var_dump($c); // NULL // this is a critical error, log of zero or negative number is undefined echo "----\nvector d - fatal error\n"; /* log(x) for x <= 0 is undefined, you used: scale = $scale" */ $d = scale_by_log($a, -2.5); var_dump($d); // Never reached ?> Code (markup): OUTPUT : vector a Array ( [0] => 2 [1] => 3 [2] => foo [3] => 5.5 [4] => 43.3 [5] => 21.11 ) ---- vector b - a notice (b = log(PI) * a) Error: [1024] Value at position 2 is not a number, using 0 (zero) File/Line: /opt/lampp/htdocs/Jagdish/test/cutom_error_handler.php/27 ....Ending Program