We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 22303 MODX Staff
    • 10,725 Posts
    Today I was reading some good arguments for and against usage of the eval() function in PHP CMS systems. After considering some published performance benchmarks (and doing a few rough benchmarks of my own) and all the potential security threats that using eval() opens the door to, I have reimplemented the Tattoo ScriptElement without the use of eval(). Instead, when saving ScriptElements (or derivatives), the script’s code will be generated into a function in a cache file with a unique name to identify the file/function.

    So long eval() and good riddance.

    So, a snippet with this content:
    $out= "<p>This is a test of nesting content in a snippet.</p><pre>[[++site_name]]
    [[++site_url]]</pre>";
    
    return $out;


    would be generated to file with:

    <?php
    function script8_0_1($scriptProperties= array()) {
    global $cms;
    if (is_array($scriptProperties)) {
    extract($scriptProperties, EXTR_SKIP);
    }
    $out= "<p>This is a test of nesting content in a snippet.</p><pre>[[++site_name]]
    [[++site_url]]</pre>";
    
    return $out;
    }
    ?>
    


    and then simply included and called by script name when processing:

    ...
    
    if ($instanceResult= @ include_once($this->scriptFileName)) {
      $this->instanceOutput= $scriptName($this->instanceProperties);
     ...
    
    
      • 32241
      • 1,495 Posts
      Cool.
      Way to go!

      I think this is the best approach, as I’ve been researching about that too, while trying to make a Chunk Template library. It will definetely increase the speed, at least half time faster than using eval.

      Keep em coming Jason! wink
        Wendy Novianto
        [font=Verdana]PT DJAMOER Technology Media
        [font=Verdana]Xituz Media
        • 34162
        • 1 Posts
        Good going! Jason.
          • 1764
          • 680 Posts
          Very cool. The heavy use of eval has scared me from a security standpoint for a long time. It’ll be good to get rid of it.

          I do have one question though. Why have a wrapper function in the include file? Why not just have an if(!inside_modx()) { die(); } line at the top of the file. I just wonder if the wrapper function wouldn’t cause headaches with variable scope and other things. Plus I’m not sure you can define classes inside of functions.

          If you were to ditch the wrapper function I suppose you’d have to use output buffering or $modx->output or something like that. I’m not convinced either way but I thougt I’d throw it out as food for thought.

          The one thing you want to be especially careful of is that someone couldn’t call the php file directly and that you couldn’t get at the source code by having it in a non-php file.

          Update:
          Just tested it out and you can create classes inside of functions, so that’s not an issue.
            • 22303 MODX Staff
            • 10,725 Posts
            Quote from: aNoble at Feb 15, 2006, 07:00 PM

            I do have one question though. Why have a wrapper function in the include file? Why not just have a if not in MODx die line at the top of the file. I just wonder if the wrapper function wouldn’t cause headaches with variable scope and other things. Can you define classes inside of functions?

            If you were to ditch the wrapper function I suppose you’d have to use output buffering or $modx->output or something like that. I’m not convinced either way but I thougt I’d throw it out as food for thought.
            I chose the wrapper function because I read in the PHP docs today that you in fact can define classes and functions inside of functions, which I previously was not aware of. That’s actually very cool, and helped produce what I think is a fairly elegant and robust alternative to eval(). In fact, I think the wrapper function is an added security benefit, as it also protects the globals and locals from the class method in which it is being included. The one drawback is that it will allow access to all properties and methods of the Element class, but I cannot come up with a scenario where this would be a vulnerability or disadvantage; in fact it might bring into play some very interesting design possibilities when adding a robust event structure in place, since PluginElements extend the functionality of ScriptElements and will also make use of this feature.

            Quote from: aNoble at Feb 15, 2006, 07:00 PM

            The one thing you want to be especially careful of is that someone couldn’t call the php file directly and that you couldn’t get at the source code by having it in a non-php file.
            I thought about this, but what harm is there in calling such a script directly (they are in script files with obscure names based on various primary keys in the object model? All it does is produce the function, which could be called only out of context and would simply not work without the surrounding class structure. The whole system depends on one single global element, $cms, and this is essentially assurance that nothing can be done anywhere in the class structure without a valid $cms instance. But I’m no security expert...so I could be overlooking something important here wink
              • 32241
              • 1,495 Posts
              Just a simple thought, why don’t we use EXTR_PREFIX_ALL for the extracting associative array?

              I think it will be awesome to have predefine prefix such as ’param_’, so we know which one comes from parameters. To ensure easy readability from the code and enforcing a tight rules for creating extension for Tattoo.

              It’s just a thought thought.
                Wendy Novianto
                [font=Verdana]PT DJAMOER Technology Media
                [font=Verdana]Xituz Media
                • 22303 MODX Staff
                • 10,725 Posts
                I don’t think it’s necessary Wendy, as being embedded in a function already protects you from existing globals or locals in the calling function. It would also require massive refactorings to the existing Snippets.

                In my experience, good design and carefully chosen semantics are simple practices to address code readability that should be reinforced by example, and not enforced by explicit rules. I see them as ever-evolving targets that when enforced by explicit rules instead of clearly stated, simple principles, can limit flexibility and ultimately the usefulness of the tool to potential audiences.
                  • 32241
                  • 1,495 Posts
                  Ok, I will second that.
                  Personally, I never disagree with your comments/suggestions, except for the IRC thing, wink

                  Anyway, nice work!

                  PS: Still amaze with the flexibility of php (coming from .Net).
                    Wendy Novianto
                    [font=Verdana]PT DJAMOER Technology Media
                    [font=Verdana]Xituz Media
                    • 1764
                    • 680 Posts
                    Quote from: OpenGeek at Feb 15, 2006, 07:13 PM

                    I chose the wrapper function because I read in the PHP docs today that you in fact can define classes and functions inside of functions, which I previously was not aware of.

                    I did not know that either but I tested it out and it does work. Pretty cool actually. I suppose it makes sense since functions can be wrapped in other function or inside conditional statements. After thinking through it I agree with you that wrapping the snippet in a function is a good way to go. I can see a few advantages to handling it that way. And since the new API will be completely OO I’d assume that there will be a lot less varriables floating around that would have to be accessed by a snippet and more object properties and methods would be able to be used (for instance being able to define a new instance of the language object instead of counting on a $_lang variable), so scope should not be such an issue.

                    Quote from: OpenGeek at Feb 15, 2006, 07:13 PM

                    I thought about this, but what harm is there in calling such a script directly (they are in script files with obscure names based on various primary keys in the object model? All it does is produce the function, which could be called only out of context and would simply not work without the surrounding class structure. The whole system depends on one single global element, $cms, and this is essentially assurance that nothing can be done anywhere in the class structure without a valid $cms instance. But I’m no security expert...so I could be overlooking something important here wink

                    I agree. I wasn’t saying that there was any security risk just something to be careful of. And actually I think it’s much better from a security standpoint to use function wrappers.

                    I think that getting rid of eval() will be a huge security improvement. The sad fact of the matter is that most MODx sites are very insecure. Most people set 777 permissions on their config.inc.php (which means anyone with access to the server can read it), and if you get the MySQL password and access to the database at any level (command line, phpMyAdmin, or anything else) you can run arbitrary PHP code on the server because of the eval() functions run against the database.
                      • 22303 MODX Staff
                      • 10,725 Posts
                      Quote from: aNoble at Feb 15, 2006, 10:55 PM

                      And since the new API will be completely OO I’d assume that there will be a lot less varriables floating around that would have to be accessed by a snippet and more object properties and methods would be able to be used (for instance being able to define a new instance of the language object instead of counting on a $_lang variable), so scope should not be such an issue.

                      In fact, I’m about to start another thread on a proposed Tattoo Lexicon ($cms->lexicon), which will replace $_lang (along with the idea of culture, which is a little more fine grained than just language in the localization and internationalization fronts) -- I’ve got some interesting ideas on supplementing translation data from the DB with traditional style array files and adding exhaustive metadata facilities to it so you can essentially build multilingual dictionaries and support searches that can use fancy lexical analysis across localized sets of information. I’ll stop there before I continue off-topic... lipsrsealed