Disable echo and print in PHP

17,386

Solution 1

At the end there is no effective way to achieve this, because at least echo is not a function, but a language construct, that cannot get disabled. You may play around with output buffering (ob_start() and such), but that will not prevent other code to disable the output buffering again.

In my eyes there is no way around but to make sure, there is only "good code". I don't know, what you mean by "prevent the client", but I would not execute arbitrary code anyway. And if its written by disciplined developers and its tested, there should be no problem then.

Solution 2

Other than editing and recompiling, I don't believe you can disable functions that output. For functions that bypass output buffering, your SOL.

You can, however, use inline output buffering to control non-header output. The best part is it's nesting capability:

ob_start();
echo 'The first output!',"\n";

ob_start();
echo 'The second output.';

$output2 = ob_get_clean();

ob_flush();

echo $output2;

will output:

The first output!
The second output.

Solution 3

What you want to do - prevent outputting at runtime - isn't possible. It just isn't going to happen. You can get very close if you do these two things though: audit the code for keywords that can produce output, and buffer output while preventing access to the output buffer control functions.

  1. Audit the code programmatically to make sure certain untrappable situations don't exist (it's up to you to cache the result of that audit efficiently, or just eat the cost of auditing on every page view - not recommended).

    You can use token_get_all() to audit for output keywords such as T_ECHO and T_PRINT (here is a list of all possible tokens). Don't try to disable access to anything but keywords here, there's too many ways to trick that (eval(), variable variables, data:// streams, etc.) You're only blocking certain keywords here.

    Don't forget T_INCLUDE, T_INCLUDE_ONCE, T_REQUIRE, and T_REQUIRE_ONCE. Not only could these be used to include unaudited code (such as PHP code written to a temp file then included), but using some of the more advanced file wrappers, these themselves can be used to produce output.

  2. Use the PHP ADB extension to disable access to certain methods by renaming them. Don't try to disable output functions, it's just not going to work, there's too many ways to generate output. Pick out the special ones like set_cookie() and header(), but for actual output, there's innumerable ways to produce output. The only surefire way to block this is to use output buffering, but disable access to the output buffer control methods so they have no way to bypass buffering.

    class YourApplicationControllingClass {
    
        final protected function callUserCode($pathToUserCodeFile) {
            // We want this to be a local variable so there's no way to get to it
            // with PHP Reflection
            $suspender = new SuspendFunctions();
    
            ob_start();
    
            // You may need to add more here, this is just my superficial pass
            $suspender->suspend("ob_clean", "ob_end_clean", "ob_end_flush", "ob_flush", 
                    "ob_get_clean", "ob_get_contents", "ob_get_flush", "ob_get_length",
                    "ob_get_level", "ob_get_status", "ob_implicit_flush", "ob_list_handlers",
                    "ob_start", "output_add_rewrite_var", "output_reset_rewrite_vars",
                    "set_cookie", "set_raw_cookie", "header_register_callback", "header",
                    "header_remove", "http_response_code", "register_shutdown_function",
                    "register_tick_function", "unregister_tick_function", "set_error_handler",
                    "restore_error_handler", "set_exception_handler", "restore_exception_handler"
                    );
    
            $this->callUserCodeSandbox($pathToUserCodeFile);
            // Restore our original execution environment
            $suspender->resume();
    
            $content = ob_get_clean();
            // If you want to be aggressive, check to see if they produced any output
            // and blacklist them if they even try.
            if ($content !== '') $this->blacklistUserCode($pathToUserCodeFile);
        }
    
        private function callUserCodeSandbox($pathToUserCodeFile) {
            require($pathToUserCodeFile);
        }
    }
    
    final class SuspendFunctions {
        private $suspendedFunctions = array();
    
        /**
        * Suspends certain functions from being executable.
        * @param string $function,... Names of functions to suspend, you may pass multiple
        * @return void
        */
        function suspend($function) {
            $functions = func_get_args();
            foreach($functions as $function) {
                // Make sure we don't double-suspend a function
                if (isset($this->suspendedFunctions[$function])) continue;
    
                // Make new names unguessable, and make it very unlikely that we end up with a collision.
                $newName = '_'.md5($function.microtime(true).mt_random());
    
                // Rename to the unguessable name
                rename_function($function, $newName);
    
                // Keep a record for ourselves what this new name is so we can resume later
                $this->suspendedFunctions[$function] = $newName;
            }
        }
    
        /**
        * Resumes functions for calling
        */
        function resume() {
            foreach($this->suspendedFunctions as $function=>$newName) {
                rename($newName, $function);
                unset($this->suspendedFunctions[$function]);
            }
        }
    }
    

Just be aware, no matter how good you are at this, there's almost certainly going to be a way to bypass (for example, maybe their code patches the content of one of your application's files to permit output again). PHP is too flexible to lock this down solidly. PHP had a similar project called Safe Mode, which they eventually abandoned because it was impossible to totally securely lock everything down. As long as the user has a full execution environment, anything you can do to block them, they can undo. Very unwise in general to execute user contributed code without hand-auditing each and every line (and even dangerous then).

Solution 4

do it this way :

    function trace($message) {
      $echo = true;
      if ($echo)
      echo $message . "<br>";
    }

then just call trace("your message"); anytime you need it, and switch $echo to false to disable it globally

Share:
17,386

Related videos on Youtube

RobertPitt
Author by

RobertPitt

My Home Page Admin Spot My Proposals: Code Review (Beta) Autism Followed Proposals: How stuff works DJing Please feel free to follow any of the above if you find them interesting. I am a 21 year old programmer who is still learning the major parts of programming such as Architecture, I hope I can learn from her and help others in the mean time !. I work within an ICT Enviroment, regarding Curriculum and Corporate netowrks, Im currenlty in control over 25 Servers and a 16 Hop network with 12 switch rooms, we look after networks work a large city within the UK. Languages: HTML CSS Javascript PHP C# (.NET) Programming: System Architecture Pattern Design MVC Framework ORM Mapping.

Updated on June 01, 2022

Comments

  • RobertPitt
    RobertPitt almost 2 years

    This may seem like a funny question but in fact it's not, I would like to disable echo, print and other functions that may output to the buffer such as readfile.

    The reason why I would like to do this is to prevent the client from using echo or print outside the rules of my application, forcing them to compile their contents and send it to the output class, so that the whole buffer is managed.

    Now I know I can set up an output buffer at the start of my script and throw away any content, but this will not include things such as header and set_cookie, so my question may be interpreted as How can I control the buffer for the head of the response

    Is there any possible way to manage all aspects of PHP's outputting, such as assign a callback to the main buffer rather then just the body of response?

    • icktoofay
      icktoofay almost 13 years
      @waitinforatrain: It's a keyword.
    • Gromski
      Gromski almost 13 years
      I think there are way too many ways to output things than you can possibly think of and intercept, so any solution would be an imperfect solution anyway. Discarding an output buffer seems like the best strategy to me.
  • RobertPitt
    RobertPitt almost 13 years
    when my application get's released there will be modules, libraries etc that will be released by developers that I have no control over, to force them developers not to cause errors within the context of the site owner, i was looking into totally managing the output buffer, but it does seem like there is no good way of handling this.
  • RobertPitt
    RobertPitt almost 13 years
    if you read my question i did state that im aware of this, but this has no effect on functions like 'set_cookie' etc
  • Gromski
    Gromski almost 13 years
    @Robert Short of inventing your own limited DSL you probably won't be able to restrict developers in any case.
  • KingCrunch
    KingCrunch almost 13 years
    @RobertPitt: Sounds like there should be a more effective quality management instead. When they can't prevent themselves from using echo, even when the developer guidelines of the modules tell them to not to use it, I don't know how good theire modules get at all (not only the echo stuff) ... As soon as the modules throw errors (headers already sent and such) they can get treated as "buggy".
  • Bryan Agee
    Bryan Agee almost 13 years
    If you read my answer, your only option for that portion is to edit and recompile the source. The nested buffering speaks to possible improvements for the rest. I will clarify.
  • Sabeen Malik
    Sabeen Malik almost 13 years
    @RobertPitt I am not aware of the full situation but may be an automated module quality control system can be introduced. Where they have to get the module approved before it goes live. This automated test script can check for certain keywords in the script and tell them to fix the issues before it can be marked as 'enabled', ensuring somewhat the idea of 'good code'