2

I have a PHP class file that is used as an include both through a web server and by a cron process. I am looking for a way to add some code to the head of the script so that I can detect if the script is being launched directly from the command line instead of being included in another script. This way I can make testing a bit easier by calling the script directly and having a function instantiate the object and execute some code on it without needing to create a wrapper script for it.

I tried using if (php_sapi_name() == 'cli') { but that tests true even if the script is being included in another script that was called from the command line.

hakre
  • 193,403
  • 52
  • 435
  • 836
Wige
  • 3,788
  • 8
  • 37
  • 58
  • This is a duplicate. See http://stackoverflow.com/questions/2397004/php-check-if-file-is-loaded-directly-instead-of-including for an answer. There are a few valid ones. – Ryan Matthews Apr 20 '11 at 15:33
  • 3
    Nope, not a duplicate, the other question is different. – Capsule Apr 20 '11 at 15:42
  • Isn't that more about detecting (and preventing) direct access through Apache, rather than what I want to do, detecting and performing additional operations when the file is directly accessed at the command line? – Wige Apr 20 '11 at 15:47
  • exactly. Your question is definitely not a duplicate of that one. – Capsule Apr 20 '11 at 15:49

5 Answers5

5

Checking that $argv[0] is set lets you know if things were invoked from the command line; it does not tell you if the file was invoked directly or if it was included from another file. To determine that, test if realpath($argv[0]) == realpath(__FILE__).

Putting it all together:

if (isset($argv[0]) && realpath($argv[0]) == realpath(__FILE__))
    // This file was called directly from command line
Alexander Garden
  • 4,468
  • 3
  • 31
  • 25
  • This is the real answer. `$argv[0]` will be set on both the file that's being called through the cli and scripts that will be included by that script. But on all scripts `$argv[0]` will be set with the same filename, the one that's being directly called. `__FILE__ != $argv[0]` on included/required scripts. – Sdlion May 01 '17 at 22:29
3

You can check for the presence of $argv. If $argv[0] is set (the script name), your script is run from the command line.

jeroen
  • 91,079
  • 21
  • 114
  • 132
  • Won't this still test true if the script is included by another script that was called from the command line? Although I could check the value of $argv[0] if it is set... Hm... – Wige Apr 20 '11 at 15:43
  • @Wige It´s a global variable so if your script is called from another script that is run from the command line, it will still exist. – jeroen Apr 20 '11 at 15:45
  • This looks like the closest solution so far. What seems to work at the moment is `if (isset($argv[0]) && strpos($argv[0], 'file.class.php') > 0) {` This method seems to be the best to always detect if the file is being called directly from the command line. – Wige Apr 20 '11 at 15:59
  • @Wige Yes, you´ll have to add a second if the script that includes it can also be run from the command line. – jeroen Apr 20 '11 at 16:04
1

You could test if $_SERVER['DOCUMENT_ROOT'] is empty. It will be empty in the command line execution since it's a variable predefined by apache.

What's interesting is $_SERVER['DOCUMENT_ROOT'] is defined but empty. I would have guessed it wouldn't be defined at all when using the cli.

You could also test if $argv is defined or its size (at least 1 when using CLI). I didn't test when including the file but if defined, sizeof($argv)would definitely be 0.

Other possible tests are $_SERVER['argc'] (0 when executed by a server, 1 when executed from CLI) and a strange $_SERVER['_'] defined to the path to the PHP binary, which is not defined at all when served.

To conclude, I would rely on $_SERVER['argc'] (or $argc) which is a direct count of the number of arguments passed to the command line: will always be 0 when the script is served. Relying on $argv is more complicated: you have to test if $argv[0] is set or if sizeof($argv) is > 0.

Capsule
  • 6,118
  • 1
  • 20
  • 27
0

I have successfully used if (defined('STDIN')) as such a check. STDIN will be defined if the script is run from a shell, but not if it's in a server environment.

As you can see here and at the link Ryan provided in his comment, there are lots of possibilities.

eaj
  • 2,576
  • 1
  • 20
  • 42
0
if($_SERVER['SCRIPT_FILENAME']==__FILE__){
   // Directly
}else{
   // Included
}
Alvy
  • 11
  • 1
  • 1
    When answering, it's recommended to share some context instead of just posting a snippet. [Check this article](https://stackoverflow.com/help/how-to-answer) to learn how to write an answer. – Andrea Olivato Apr 06 '22 at 01:11