3

I am trying to work out how to interpret PHP's include construct, e.g. whether it is textual inclusion, when it is evaluated etc. As usual, the documentation is rather informal and vague.

Based on experimentation, it seems to be syntactic sugar. Specifically, the construct

include 'Baz.php'

is an expression which can be replaced with

eval('?>' . file_get_contents('Baz.php',  FILE_USE_INCLUDE_PATH))

Is this correct? Is this substitution true in the general case, or just in my tests?

Edit: as bwoebi notes, this is not generally true since the evaluated code does not have the same __DIR__ and __FILE__ magic constants. If there were some way to set them, we could model that too.

Edit 2: this question is a duplicate of this one: Equivalent of include using eval. However, all the answers there appear to omit bwoebi's point about the file path context.

Community
  • 1
  • 1
jameshfisher
  • 34,029
  • 31
  • 121
  • 167
  • 1
    No, with `__DIR__` and `__FILE__` you're out of luck. (I doubt that even runkit would work for these __compile time__ constants) – bwoebi May 15 '14 at 15:03

2 Answers2

2

Yes, that should be generally true.

The only differences are:

  • file context (it's now eval()'ed code, not code from that file)
  • relative paths: when you include files in other directories and they use theirselves relative paths, the file it points to might now not be found anymore
  • file_get_contents() is not affected by allow_url_include ini setting (though allow_url_fopen affect both)
bwoebi
  • 23,637
  • 5
  • 58
  • 79
  • @jameshfisher to circumvent that one, you actually could just use `chdir()` before `eval()` here. (and reset it later) – bwoebi May 15 '14 at 14:59
  • I'm not sure that works; the `__FILE__` and `__DIR__` constants seem to stay the same? – jameshfisher May 15 '14 at 15:03
  • `__FILE__` and `__DIR__` will match the file and directory of the included/required file. Also, relative paths only work if you have put `.` (shorthand for current directoy) in your `include_path`. Its usually not safe to rely on it being set as such. – Oscar M. May 15 '14 at 15:08
  • @jameshfisher Just asked a bit around, but there is no way to override __compile time__ constants. Impossible. – bwoebi May 15 '14 at 15:17
0

Other things to note are:

  • This will break PHP Opcode caching, as the file contents are read into memory as text, and then parsed/evaluated, producing a significant hit on performance if you are not expecting it. As mentioned in this question.
  • Parse errors in the code will not be fatal to the rest of the script, which has the side-effect of allowing the script execution to continue, even though logic that is expected to have happen may not have. (This may be true of other types of errors as well).
  • Error reporting will not resolve to the correct file/line, and therefore, debugging will become difficult.
  • This will not support the _once construct, which allows including/requiring files strictly once. This means duplicate class/function declarations will be fatal and/or behave unexpectedly.

I am certain there are other considerations that make this inadvisable as well. Without knowing your desired functionality or the reason you need to do this, giving you a helpful answer is difficult.

The best part of utilizing eval is the recovery from errors (if you could call this a "best" thing). If that is the benefit you are trying to take advantage of, however, this kind of is your only option.... Unfortunately...

Community
  • 1
  • 1
Mike
  • 1,968
  • 18
  • 35
  • error reporting only will contain `eval()'ed code` (as I noted in my answer), but the line is still correct. The `_once` construct you usually can emulate in a function. For everything else I agree. – bwoebi May 15 '14 at 15:36
  • The line of the `eval` statement, but will the line on which the error occurred in the `eval`'d be correct? Emulation is great, but why emulate all the functionality of the Standard Library function when you can just use it it's self? Emulating all of the checks and procedures of the function is possible, but not native, and thus very inefficient. As a learning exercise, I can see that, but otherwise, impractical. – Mike May 15 '14 at 16:04