jchook Posted July 11, 2010 Share Posted July 11, 2010 str_to_array() Since I think this is an important feature that can be used in many ways (including WordPress Filters / Plugins), I thought I would come on here and post my str_to_array() function. [it's my first post. I don't really need help at the moment, but the PHP Snippets forum is READ ONLY, so here I am.] Using eval() as suggested here is dangerous. If you ran CMS content through eval(), any php-savvy author on the system could effectively gain admin access to the depths of your CMS and beyond. Hence my need for this function. Features Simplified syntax that is whitespace-insensitive like PHP No regular expressions, so it's lightweight. Eval functionality if you want it. The functionality can be disabled either through an if-statement or by commenting out that portion of the code. Nested arrays for more complex applications Escape character support (\) for putting special characters in your array content # function str_to_array() # # Converts a simple string expression into an array. # Supports simple syntax, nested arrays and nested PHP. # # @version 1.0 # @author Wesley Roberts # @date July 11, 2010 # @link http://fire.cowfight.com/ # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # function str_to_array($str, $var_sep=',', $val_sep='=') { # Defaults if (!is_string($str)) return null; $r = array(); # Whitespace $skip = array(" ","\t","\n","\r"); # Trim whitespace $str = trim($str, implode($skip)); # Remove array notation if necessary # NOTE that trim will not work here # AND they are individual on purpose if (substr($str,0,1) == '[') $str = substr($str,1); if (substr($str,-1,1) == ']') $str = substr($str,0,-1); # Always end the string with $var_sep $str .= $var_sep; $len = strlen($str); # Defauts $buf = ''; # buffer $key = 0; # next array key $inc = 0; # next numeric array key $esc = false; # escaped char? # Go through each character for ($i=0; $i<$len; $i++) : if ($esc) : $buf .= $str[$i]; $esc = false; continue; endif; switch($str[$i]): # Association operator case $val_sep: if (!empty($buf)) : $key = $buf; $buf = ''; endif; break; # PHP! Note: this clears the buffer!!! # If you need to prefix your results, # do it within the braces. case '{' : $end = str_delimiter_pos_r($str, $len, $i, '{', '}'); $buf = eval(substr($str, $i+1, $end-$i-1)); // excluding braces $i = $end; break; # Sub-array notation is recursive case '[': $end = str_delimiter_pos_r($str, $len, $i); $buf = str_to_array(substr($str, $i, $end-$i)); $i = $end; # will be incremented break; # Quotations to have spaces case "'": case '"': $end = str_delimiter_pos_r($str, $len, $i, $str[$i], $str[$i]); $buf = substr($str, $i+1, $end-$i-1); // excluding quotes $i = $end; break; # Escape character case '\\': if (!$esc) : $esc = true; $buf .= $str[$i+1]; $i++; else : $buf .= '\\'; endif; break; # Variable separator case $var_sep : $r[$key] = $buf; if (is_numeric($key)) $inc++; $key = $inc; $buf = ''; break; # Default default: if (! in_array($str[$i], $skip)) $buf .= $str[$i]; break; endswitch; endfor; # Return the final value return $r; } # THIS FUNCTION IS REQUIRED BY str_to_array() # Looks for the closing delimiter ($rchar). # Assumes that the first char ($offset=0) is the opening delimiter ($lchar). # function str_delimiter_pos_r(&$str, &$len=0, $offset=0, $lchar='[', $rchar=']') { $r = $offset+1; for ($r; $r<$len; $r++) : # Escape character if ($str[$r] == '\\') $r++; # Sub delimiters # (this only works when the delimiters are distinct) elseif (($str[$r] == $lchar) && ($lchar != $rchar)) $r = str_delimiter_pos_r($str, $len, $r, $lchar, $rchar); # Whew. We made it. elseif ($str[$r] == $rchar) return $r; endfor; return $len; } It's probably best to learn by example for this one: # The simplest usages str_to_array('[]') // Array () str_to_array('[something]') // Array ( 'something' ) str_to_array('["something with spaces"]') // Array ( 'something with spaces' ) str_to_array('[ a=1, b=2, c=3]') // Array ( 'a'=>'1', 'b'=>'2', 'c'=>'3' ) For a more comprehensive display of its capabilities print_r(str_to_array(' [ first = [assigned, associatively], [an,array,all,alone], "something else" = [ array = values ], "just a value", "some php generated text" = { return "Today\'s Date Is ".date(\'m-d-Y\'); } ] ')); The above code will output: /* OUTPUT: Array ( [first] => Array ( [0] => assigned [1] => associatively ) [0] => Array ( [0] => an [1] => array [2] => all [3] => alone ) [something else] => Array ( [array] => values ) [1] => just a value [some php generated text] => Today's Date Is 07-11-2010 ) See Also http://www.phpfreaks.com/forums/index.php/topic,286916.0.html Quote Link to comment https://forums.phpfreaks.com/topic/207446-str_to_array-convert-a-string-to-an-array/ Share on other sites More sharing options...
wildteen88 Posted July 11, 2010 Share Posted July 11, 2010 Your function is sort of similar to json_encode and json_decode. Cant see the use in your function though. Where would I use this? Quote Link to comment https://forums.phpfreaks.com/topic/207446-str_to_array-convert-a-string-to-an-array/#findComment-1084594 Share on other sites More sharing options...
jchook Posted July 12, 2010 Author Share Posted July 12, 2010 You would use this function to accept user input in a CMS context. For example, suppose you have a gallery module that your users would like to include in their page content. You can specify a content filter that accepts input in a fashion that is very easy for a user to write (about as easy as BBCode). This is a suggested syntax, though the syntax can be customized (the function is rather simple). [my_module_name, title = "My Custom Title", gallery = "My First Gallery", height = 300, width = 500 ] Moreover, since it is fairly robust (though certainly could use some improvements), this type of user input can be standardized across many plugins or modules to provide the user with some level of consistency. Quote Link to comment https://forums.phpfreaks.com/topic/207446-str_to_array-convert-a-string-to-an-array/#findComment-1084642 Share on other sites More sharing options...
jchook Posted July 12, 2010 Author Share Posted July 12, 2010 Can't figure out how to edit my first post, but I made some improvements just now. I think this thing has many uses if you just think along the lines of accepting user input. Whatever though, it's useful to me! Just sharing. New in this version: true and false now evaluate as actual boolean values. To use the string versions, just put quotes around them. Fixed the empty array problem (returned an array with one element) Fixed the weird escape character business Fixed the argument order for str_delimiter_pos_r() # # function str_to_array() # # Converts an simple string expression into an array. # Supports simple syntax, nested arrays and nested PHP. # # @version 1.1 # @author Wesley Roberts # @date July 11, 2010 # @link http://fire.cowfight.com/ # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # function str_to_array($str, $var_sep=',', $val_sep='=') { # Defaults if (!is_string($str)) return null; $r = array(); # Whitespace $skip = array(" ","\t","\n","\r"); # Trim whitespace $str = trim($str, implode($skip)); # Remove array notation if necessary # NOTE that trim will not work here # AND they are individual on purpose if (substr($str,0,1) == '[') $str = substr($str,1); if (substr($str,-1,1) == ']') $str = substr($str,0,-1); # Empty? if (empty($str)) return array(); # Always end the string with $var_sep $str.= $var_sep; $len = strlen($str); # Defauts $buf = ''; # buffer $key = 0; # next array key $inc = 0; # next numeric array key $esc = false; # escaped char? # Go through each character for ($i=0; $i<$len; $i++) : # Skip escaped characters if ($esc) : $buf .= $str[$i]; $esc = false; continue; endif; # Check the current character switch($str[$i]): # Association operator case $val_sep: if (!empty($buf)) : $key = $buf; $buf = ''; endif; break; # PHP! Note: this clears the buffer!!! # If you need to prefix your results, # do it within the braces. case '{' : $end = str_delimiter_pos_r($str, $i, '{', '}', $len); $buf = eval(substr($str, $i+1, $end-$i-1)); // excluding braces $i = $end; break; # Sub-array notation is recursive case '[': $end = str_delimiter_pos_r($str, $i, '[', ']', $len); $buf = str_to_array(substr($str, $i, $end-$i)); $i = $end; # will be incremented break; # Quotations to have spaces case "'": case '"': $end = str_delimiter_pos_r($str, $i, $str[$i], $str[$i], $len); $buf = substr($str, $i+1, $end-$i-1); // excluding quotes $i = $end; break; # Escape character case '\\': $esc = true; break; # True case 't': case 'T': $look_for = 'true'; $look_len = strlen($look_for); if (strtolower(substr($str, $i, $look_len)) == $look_for) : $buf = true; $i += $look_len - 1; # this will be incremented endif; break; # False case 'f': case 'F': $look_for = 'false'; $look_len = strlen($look_for); if (strtolower(substr($str, $i, $look_len)) == $look_for) : $buf = false; $i += $look_len - 1; # this will be incremented endif; break; # Variable separator case $var_sep : $r[$key] = $buf; if (is_numeric($key)) $inc++; $key = $inc; $buf = ''; break; # Default default: if (! in_array($str[$i], $skip)) $buf .= $str[$i]; break; endswitch; endfor; # Return the final value return $r; } # Looks for the closing delimiter ($rchar). # Assumes that the first char ($offset=0) is the opening delimiter ($lchar). # function str_delimiter_pos_r(&$str, $offset=0, $lchar='[', $rchar=']', &$len=0) { $r = $offset+1; for ($r; $r<$len; $r++) : # Escape character if ($str[$r] == '\\') $r++; # Sub delimiters # (this only works when the delimiters are distinct) elseif (($str[$r] == $lchar) && ($lchar != $rchar)) $r = str_delimiter_pos_r($str, $r, $lchar, $rchar, $len); # Whew. We made it. elseif ($str[$r] == $rchar) return $r; endfor; return $len; } Quote Link to comment https://forums.phpfreaks.com/topic/207446-str_to_array-convert-a-string-to-an-array/#findComment-1084657 Share on other sites More sharing options...
jchook Posted July 12, 2010 Author Share Posted July 12, 2010 New in Version 1.2 Now semi-whitespace-sensitve -- that is, whitespace is trimmed from the edges of values and keys. This greatly simplifies the syntax requirements and makes for generally easier writing and reading Supports solo variables such as [ $var_name ] Supports in-line variables wrapped in percent-signs such as %var_name% Extracts additional variables to the local symbol table for use in building values or keys Improved numeric key handling Fixed poor support for true and false The Code # # function str_to_array() # # Converts an simple string expression into an array. # Supports simple syntax, nested arrays and nested PHP. # # @version 1.2 # @author Wesley Roberts # @date July 11, 2010 # @link http://fire.cowfight.com/ # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # function str_to_array($str, $opts=array()) { # Defaults if (!is_string($str)) return null; $r = array(); $default_opts = array( 'var_sep' => ',', 'val_sep' => '=', 'allow_eval' => true, ); $opts = array_merge($default_opts, $opts); extract($opts); # Whitespace $skip = array(" ","\t","\n","\r"); # Trim whitespace $str = trim($str); # Remove array notation if necessary # NOTE that trim will not work here # AND they are individual on purpose if (substr($str,0,1) == '[') $str = substr($str,1); if (substr($str,-1) == ']') $str = substr($str,0,-1); # Empty? if (empty($str)) return array(); # Always end the string with $var_sep $str.= $var_sep; $len = strlen($str); # Defauts $buf = ''; # buffer $key = 0; # next array key $inc = 0; # next numeric array key $esc = false; # escaped char? $quo = false; # quoted content? (i.e. can't be keyword) $red = false; # have we read any non-space chars yet? # Go through each character for ($i=0; $i<$len; $i++) : # Skip escaped characters if ($esc) : $buf .= $str[$i]; $esc = false; continue; endif; # Check the current character switch($str[$i]): # Association operator case $val_sep: if (!empty($buf)) : $key = trim($buf, implode($skip)); $red = false; $buf = ''; endif; break; # PHP! Note: this clears the buffer!!! # If you need to prefix your results, # do it within the braces. case '{' : $end = str_delimiter_pos_r($str, $i, '{', '}', $len); if ($allow_eval): $buf = eval(substr($str, $i+1, $end-$i-1)); // excluding braces $i = $end; endif; break; # Sub-array notation is recursive case '[': $end = str_delimiter_pos_r($str, $i, '[', ']', $len); $buf = str_to_array(substr($str, $i, $end-$i), $opts); $i = $end; # will be incremented break; # Variables with % case '%': $end = str_delimiter_pos_r($str, $i, '%', '%', $len); $var = substr($str, $i, $end-$i); $buf = $$var; # variable variable $i = $end; # will be incremented break; # Quotations allow spaces case "'": case '"': $end = str_delimiter_pos_r($str, $i, $str[$i], $str[$i], $len); $buf = substr($str, $i+1, $end-$i-1); // excluding quotes $i = $end; # Double quotes can be evaluated if ($str[$i] == '"' && $allow_eval) $buf = eval('return "'.$buf.'";'); else $quo = true; # quoted break; # Escape character case '\\': $esc = true; break; # Variable separator (i.e. clear buffer) case $var_sep : # Keywords are possible when the input # is a single non-quoted word if (!$quo): if ($buf == 'true') : $buf = true; elseif ($buf == 'false') : $buf = false; elseif ($buf[0] == '$') : $var = substr($buf, 1); $buf = $$var; # variable variable endif; # If we're not in quotes, be more strict about # whitespace, but allow it in the middle. else : $buf = rtrim($buf, implode($skip)); endif; # If the key was an integer, then we need # to find the next available integer for # the next entry's key if (is_int($key)) : do { $inc++; } while(array_key_exists($inc, $r)); endif; # Dump buffer into the returned array # associated with the appropriate key $r[$key] = $buf; # Prepare the next key $key = $inc; # Clear the buffer for the next entry $buf = ''; $red = false; break; # Default. If we have started reading content # you can count in the spaces. Otherwise, f spaces default: if ($red || !in_array($str[$i], $skip)) : $red = true; $buf .= $str[$i]; endif; break; endswitch; endfor; # Return the final value return $r; } # Looks for the closing delimiter ($rchar). # Assumes that the first char ($offset=0) is the opening delimiter ($lchar). # function str_delimiter_pos_r(&$str, $offset=0, $lchar='[', $rchar=']', &$len=0) { $r = $offset+1; for ($r; $r<$len; $r++) : # Escape character if ($str[$r] == '\\') $r++; # Sub delimiters # (this only works when the delimiters are distinct) elseif (($str[$r] == $lchar) && ($lchar != $rchar)) $r = str_delimiter_pos_r($str, $r, $lchar, $rchar, $len); # Whew. We made it. elseif ($str[$r] == $rchar) return $r; endfor; return $len; } Demonstration of Improvements # version 1.1 syntax # version 1.2 syntax [ "some long key" = "some long string" ] [ some long key = some long string ] [ { return $variable; } ] [ $variable ] [ { return "something with $variables"; } ] [ something with %variables% ] [ "something with $variables" ] Quote Link to comment https://forums.phpfreaks.com/topic/207446-str_to_array-convert-a-string-to-an-array/#findComment-1084722 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.