Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 7 of 7
  1. #1
    Regular Coder Custard7A's Avatar
    Join Date
    Jul 2010
    Location
    Australia
    Posts
    286
    Thanks
    32
    Thanked 33 Times in 33 Posts

    Managing Broken Includes / Requires

    Hi coding gurus! I'm trying to create a method of including a PHP script to my files that allows me to handle what happens when something goes wrong with the inclusion. Blank pages when something goes wrong is lame!
    Not really necessary; It's an experiment more than a problem, I like the idea of covering everything I can. I also make thing harder on myself than I need to, because that seems to be a great way to learn things.

    Let's say I put this code at the top of my files:
    PHP Code:

     
    if(include 'alpha.php')
     { echo 
    'Success'; } // In practical use I would initialize some objects or something.
     
    else { die('Could not include vital script.'); } 
    So far it works like a require, but allowing me to say something when it doesn't work. However, I wanted to send the user something a bit more comprehensive and useful, than a little string.

    I didn't want to do something like this either:
    PHP Code:

     
    if(include 'alpha.php')
     { echo 
    'Success'; }
     else { die(
    '<span style=\"ect\"> Formatted message. </span>'); } 
    In real-world use the above would be a big mess of code, as well as being just awful if I ever wanted to change the error message at all (As would the first solution, for that matter).
    Hence, my ideal result would be to trigger a HTTP 500 error page, which as well as having all the information the user needs to know (Even if it's not technically a server error? I don't know.), is also set up to record the error and give the user some useful options (Go to home-page, retry page, ect). It didn't have to be a HTTP 500, I'm just using it for the purposes of trying this.

    My first response was something to the effect of: (Error link for example purposes only)
    PHP Code:

     
    if(include 'alpha.php')
     { echo 
    'Success'; }
     else { 
    header('error.php?id=500&cause=include_failed'); } 
    This returns three warnings:
    Warning: include(alpha.php) [function.include]: failed to open stream: No such file or directory in..
    Warning: include() [function.include]: Failed opening 'alpha.php' for inclusion..
    Warning: Cannot modify header information - headers already sent by.. (The include line)

    Note: The file doesn't exists there, I'm testing the else by including a non-existent file. So basically it's just headers already sent by the include, which wasn't totally unexpected. (Not that I thought very hard when the headers would be sent here).

    However, by accident I discovered this produces an error 500 if the file comes back false:
    PHP Code:

     
    if(@include 'alpha.php'// Notice the error silencer.
     
    { echo 'Success'; }
     else { 
    header('/'); } 
    Doesn't matter what the header link is, as long as a value exists the presence of the header call causes the HTTP 500. I also tried this with "display_errors" set to off in my php.ini (Yes, it's only on for development), and it produced a HTTP 500 even without the @ silencer.

    It does make sense in a way, but not all errors send a HTTP 500 when silenced! If that were so I could be doing this simply with a @require — I don't understand why these methods are behaving differently. Perhaps, fatal errors can't return a HTTP error, but others will? I would like to understand this behavior, if anyone knows!

    One other issue I noticed with what I was trying to do, is when the include works but the script has errors, which was the other thing I wanted to catch. It will slip right through this check..

    Consider I make alpha.php this:
    PHP Code:

    <?php undefinedFunction(); ?>
    Now the script will return a fatal error, but will also return true as being included. Since that is all if(include 'alpha.php') checks for, I might as well be using a file_exists or something. How can I catch when my include script is producing errors without hard-coding return false type things into every possible instance? Perhaps I could check for a value that might be hidden if errors choke up the result (I can see that working for fatal errors, but other errors getting past..), or wrap everything in alpha.php with some sort of error catch that returns false or true?

    I thought it was time to see what other people knew about the subject. I have little experience. Please no "Your idea is terrible, just trust your includes to always work"; That's already my fall-back, I just want to be clever. I'm open to different approaches too.

  • #2
    Regular Coder poyzn's Avatar
    Join Date
    Nov 2010
    Posts
    266
    Thanks
    2
    Thanked 61 Times in 61 Posts

  • #3
    Regular Coder Custard7A's Avatar
    Join Date
    Jul 2010
    Location
    Australia
    Posts
    286
    Thanks
    32
    Thanked 33 Times in 33 Posts
    Quote Originally Posted by poyzn View Post
    Yes, I did briefly consider that, but only tried it to see the behavior once you mentioned it. I used this:
    PHP Code:

    if(file_exists('alpha.php'))
      { include 
    'alpha.php'; } 
    else { 
    header('/'); } 
    - It produces an HTTP 500 when the file doesn't exist (And used with an invalid header call like this, obviously), regardless of whether PHP error reporting is on or not. Again, I find myself confused as to why some errors send HTTP 500 and why some are content with sending a blank page. (This is even more confusing, because I expected a "Headers already sent" at least).

    - Doesn't matter to it if the file that exists is producing fatal errors or not, so it's pretty much doing the same as the if(include 'alpha.php') I was experimenting with. With the exception that it doesn't use the php.ini include path, which is kind of important. (Yeah I could get the path via ini_get, but so far using file_exists doesn't seem to solve the problem. It still seems inconsistent or 'hack-ish' getting the error this way, and can't find the status of the file.)

    Thanks anyway..

  • #4
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,994
    Thanks
    4
    Thanked 2,662 Times in 2,631 Posts
    Those headers are no good. There is no such thing as / as an interpretable HTTP header. Perhaps you mean to use a Location: directive? Headers already being sent is caused by previous output, which does include error messages. You cannot specify anything requiring headers anytime after output (sessions, cookies, header, etc), unless the output is buffered.

    You cannot do this to detect a link failure on the included script. That is an E_ERROR which is fatal for a reason, and PHP cannot continue with parsing. Because of this, there is no way to capture it at runtime. I don't even think the APD would let you evaluate and capture these, but you can execute a system call to the lint using an exec call to php.exe -l; if it returns 0, then it was syntactically accurate.

    This is a complete waste IMO. Syntactical errors should be caught during development, long before they hit a production server.

    If you insist on a check against an include instead of a forced require, I'd suggest keeping it with a defined constant. Since you are not using _once functionality, you should be doing it anyways to prevent attempts to recreate definitions to classes and functions which are fatal when attempting to do so.
    PHP Code:
    // include.php
    <?php
    if (!defined('INCLUDE_H'))
    {
        
    define('INCLUDE_H'true);
        
    // definitions
    }

    // index
    include 'include.php';
    if (!
    defined('INCLUDE_H'))
    {
        die(
    'Failed to include.');
    }
    Oldschool.

  • #5
    Regular Coder Custard7A's Avatar
    Join Date
    Jul 2010
    Location
    Australia
    Posts
    286
    Thanks
    32
    Thanked 33 Times in 33 Posts
    Oh! Thanks Fou-Lu.. A simple mistake of omitting the "Location:" directive, but it could have been making a difference. Sorry if I wasn't clear; I was aware the header call existing there was an invalid move. I was merely interested in the idea of intentionally causing a HTTP 500 error. I'd also like to clarify, that I don't like the idea of using invalid code to get results. I was more-or-less wondering if anybody had a better solution to what I was trying to do. I'm beginning to think it was a bad idea to start with.

    Please note: I am liable to be writing PHP which will then be used on a website run not by me, but by script-kiddies, and which will also be a prime candidate for further development (Possibly by said script-kiddies). I didn't want to come over as an attempt to be lazy and get away with not checking errors. I simply thought it would be nice, if my vital PHP resources aren't working right in runtime, to send the user a nice message, and to have some data to work with in regards to logging the problem.

    So I'm wasting my time with this? I don't suppose I could check anything while the include is being buffered, and still use a header redirect? (I know little about output buffering)

  • #6
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,994
    Thanks
    4
    Thanked 2,662 Times in 2,631 Posts
    Not for fatal you cannot.
    php logs its own errors as well, so you can find those either in the same directory or in the webhost's error log.

    Using file_exists and is_readable is a better option. You can branch that for an require[_once] call and use the else to display something else.

  • #7
    Regular Coder Custard7A's Avatar
    Join Date
    Jul 2010
    Location
    Australia
    Posts
    286
    Thanks
    32
    Thanked 33 Times in 33 Posts
    Mmh, I was suspecting as much from your last post. I suppose PHP's error file is my only option to log fatal errors in runtime, seeing as fatal errors always get the last word.

    That aside, at least checking the file itself seems viable. I like that last suggestion the best so far, however, I'm unfamiliar with is_readable. The documentation seems to imply the only readability it covers is the permissions, and it caches the results. I could un-cache them every time, though I'm not really concerned with permissions being changed.

    Hah, I just thought of this:
    PHP Code:

    if(file_exists('alpha.php'))
    { require_once 
    'alpha.php'; }
      else
    { require_once 
    'error.php';
      die(); } 
    // Or die at end of that file. 
    It's dynamic, isn't cluttery, and a relatively simple little file like "error.php" would be a lot easier to keep exclusive from edits and not have errors itself than hordes of really important stuff in "alpha.php".

    Is this innovative, perhaps, or am I over-looking something else?

    Edit: I remembered, file_exists doesn't use the include_path, so this solution would require a bit more.
    Last edited by Custard7A; 10-14-2012 at 04:29 AM. Reason: Note about using file_exists.


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •