Welcome Guest, Not a member yet? Register   Sign In
Custom token/template parser
#1

[eluser]Madmartigan1[/eluser]
I'm looking for a good solution for executing PHP code within database content. I'm using a WYSIWYG editor to manage page content, and need to be able to execute various CI and PHP functions.


I've used Dwoo, but I don't need a full template parsing engine.

I just want to be able to alias certain whitelisted functions and parse a (very large) string (the database content).

No IF blocks or even variables.


I've had some success and was able to do some simple single argument functions, and then switched things up and used call_user_func_array() to output some CI stuff, turning {class:method(arg)} into $this->class->method($arg), but it was very slow and rigid.

I would like to know if anyone has any advice on this, maybe some useful links or alternatives methods. I'm coming up totally dry on google.

Here is the code I'm using to parse simple tokens that represent PHP functions with one argument:

Code:
// token format {function:argument}

// This will turn {date:Y} into <?php echo date("Y"); ?>, for instance

// this is just an example of what i want to do

    private function _parse($str)
    {
        $l_delim = '{';
        $r_delim = '}';

        $parsed = preg_replace_callback(
            '/' . $l_delim . '(.*?):(.*?)' . $r_delim . '/',
            create_function('$match', 'return $match[1]($match[2]);'),
            $str
        );

        return $parsed;
    }
#2

[eluser]InsiteFX[/eluser]
Read this!

CodeIgniter Template Parser Class

InsiteFX
#3

[eluser]Madmartigan1[/eluser]
Of course I've looked at the CI template parser. I also said that I've used dwoo. I've used smarty as well. It's not even close to what I'm looking for, but thanks for the reply.

I'm trying to parse a string to extract tokens that represent functions with parameters. No loops or iterators, no outside data, no BB code.

This is working for me currently, although I haven't spent time on parsing more than one param:

Code:
// Turns {config_item:base_url} into <?php echo config_item('base_url'); ?>

    private function _parse($string)
    {

        $l_delim = '{';
        $r_delim = '}';

        preg_match_all(
            '/' . $l_delim . '(.*?):(.*?)' . $r_delim . '/',
            $string,
            $matches
        );
        
        if (empty($matches[0]))
        {
            return $string;
        }
        
                // Allowed functions
        $allowed = array(
            'config_item',
            'strip_tags'
        );

        foreach ($matches[1] as $key => $val)
        {
            if ( ! in_array($val, $allowed))
            {
                $replace[$key] = $matches[0][$key];
                continue;
            }
            $replace[$key] = call_user_func($val, $matches[2][$key]);
        }
        
        $parsed = str_replace($matches[0], $replace, $string);
        
        return $parsed;
    }
#4

[eluser]wiredesignz[/eluser]
Check the wiki for Parsers. I wrote a parser module that could easily be re-adapted as a library. It allows you to call functions using the @ prefix. ie:

Code:
{@site_url('home')}
#5

[eluser]Madmartigan1[/eluser]
Thanks, wiredesignz - I tried your code, but for some reason it was finicky, and I don't need to parse files or pass data to anything.
I also think there needs to be a whitelist of allowed functions. I was using philsturgeon's dwoo implementation with TinyMCE, until I noticed that it wasn't respecting the allowed functions list. Users were able to {exit(phpinfo())} which is not cool. I tried like hell to find the source of the issue but decided that since I'm not doing standard template parsing, a library like that is way too much anyways.

Thanks guys!
#6

[eluser]Madmartigan1[/eluser]
Just thought I'd update with the current code I've been using for anyone else looking for solutions to this.

It can't access class functions in this state, but could be easily modified (I haven't needed that feature yet). This does not support nested tokens either.

Hope this helps someone! Improvements welcome!

Code:
<?php defined('BASEPATH') OR exit('No direct script access.');

/**
* Simple token parser
*
* Convert tokens into php functions
* Modifies the original string
* Takes the first segment before the split as function name and the rest as arguments
* Does not alter the token if function not allowed, but will continue to parse other tokens
* Cannot access classes or objects directly, only user defined functions (the ones in the list)
*
* Useage:
*             $my_content = $this->model->get();
*             $this->token_parser->parse($my_content->body)->parse($my_content->title);
*             echo $my_content->body; <-- parsed string
*             echo $my_content->title; <-- parsed string
*
*/
class Token_Parser {

    private $l_delim = '{';
    private $r_delim = '}';
    private $separator = '|';

    // Key is the true function name, value is the token alias
    private $allowed_functions = array(
        'date'                =>    'date',            // native PHP function
        'base_url'            =>    'base_url',        // CI function
        'foo'            =>    'my_function',    // user defined
    );
    // EXAMPLE:        {my_function|bar|baz}        foo('bar', 'baz');
    // EXAMPLE:        {date|Y-m-d gi:a}    date('Y-m-d gi:a');
    // EXAMPLE:        {base_url}            base_url()
    
    
    /**
     * Parse a string for tokens
     * This will modify the existing string/variable
     *
     * @param        string
     * @return       object
     */
    public function parse(&$string)
    {
        // Search for tokens
        preg_match_all(
            '/'.preg_quote($this->l_delim).'(.*?)'.preg_quote($this->r_delim).'/',
            $string,
            $matches
        );

        // No tokens found
        if (empty($matches[0]))
        {
            return $this;
        }
        else
        {
            $tokens = $matches[0];
            $token_contents = $matches[1];
        }

        // Process each token
        foreach ($token_contents as $key => $val)
        {
            // Extract the arguments
            if (preg_match('/'.preg_quote($this->separator).'.*/', $val, $match))
            {
                // Functions with one or more arguments
                $function = preg_replace('/'.preg_quote($match[0], '/').'/', '', $val);

                $args = explode($this->separator, trim($match[0], $this->separator));
            }
            else
            {
                // Functions with no arguments
                $function = $val;
                $args = array();
            }
        
            // If the function is not allowed, just replace with the original string
            if ( ! in_array($function, array_keys($this->allowed_functions)))
            {
                $replace[$key] = $tokens[$key];
                continue;
            }

            $replace[$key] = call_user_func_array($this->allowed_functions[$function], $args);
        }

        $string = str_replace($tokens, $replace, $string);
        return $this;
    }

    /**
     * Generate a token code for users to copy and paste
     *
     * @param        mixed
     * @return        string
     */
    public function generate_token()
    {
        $args = (array) func_get_args();
        $code = $this->l_delim;
        $code .= implode($this->separator, $args);
        $code .= $this->r_delim;
        return $code;
    }


}
/* end file */




Theme © iAndrew 2016 - Forum software by © MyBB