an array of parameter values - php

function test()
{
$content = "lang=en]text en|lang=sp]text sp";
$atts = explode('|', $content);
}
What I'm trying to do is to allow myself to echo $param[en] to get "text en", $param[sp] to get "text sp". Is that possible?
the $content is actually from a database record.

$param = array();
$langs = explode('|', $content);
foreach ($langs as $lang) {
$arr = explode(']', $lang);
$key = substr($arr[0], 5);
$param[$key] = $arr[1];
}
This is if you are sure $content is well-formatted. Otherwise you will need to put in additional checks to make sure $langs and $arr are what they should be. Use the following to quickly check what's inside an array:
echo '<pre>'.print_r($array_to_be_inspected, true).'</pre>';
Hope this helps

if this is not hard coded string in $content
function test()
{
$content = "lang=en]text en|lang=sp]text sp";
$atts = explode('|', $content);
foreach($atts as $att){
$tempLang = explode("]", $att);
$params[array_pop(explode("=", $tempLang[0]))] = $tempLang[1];
}
var_dump($params);
}

I think in this case you could use regular expressions.
$atts = explode('|', $content);
foreach ($atts as $subtext) {
if (preg_match('/lang=(\w+)\](\w+) /', $subtext, $regs)) {
$param[$regs[0]] = $regs[1];
}
}
Although it seems that you have a bad database structure if that value comes from a database - if you can edit it, try to make the database adhere to make the database normal.

Related

PHP Properties Parser

Im making a property parser, and I want it to be able to parse a string of any length.
For example, I would like to be able to do the following call:
getDynamicProp("cheese:no;sauce:yes;chicken:brown", "sauce");
and have "yes" returned from it.
Here is what I've got so far:
function getDynamicProp($string , $property){
$args = func_num_args();
$args_val = func_get_args();
$strlen = mb_strlen($string);
$propstrstart = mb_strpos($string , $property . ":");
$propstrend1 = substr($string , $propstrstart , )
$propstrend = mb_strpos($string , ";" , $propstrstart);
$finalvalue = substr($string , $propstrstart , $propstrend);
$val = str_replace($property . ":" , "" , $finalvalue);
$val2 = str_replace(";" , "" , $val);
return $val2;
}
You can try this. The function uses explode to transform strings into arrays, which are more easily manipulable :
function getDynamicProp($string , $property){
$the_result = array();
$the_array = explode(";", $string);
foreach ($the_array as $prop) {
$the_prop = explode(":", $prop);
$the_result[$the_prop[0]] = $the_prop[1];
}
return $the_result[$property];
}
$the_string = "cheese:no;sauce:yes;chicken:brown";
echo getDynamicProp($the_string,"cheese");
echo getDynamicProp($the_string,"sauce");
echo getDynamicProp($the_string,"chicken");
I think you make it over-complicated, or I didn't understand what you want.
I will go with regex instead of making position search.
Here is what I'll use:
function getDynamicProp($string , $property){
if (preg_match('/(^|;)' . $property . ':(?P<value>[^;]+)/', $string, $matches)) {
return $matches['value'];
}
return false;
}
Check here to visualize regex
You would be better off using json_encode and json_decode if you are in control of this string. If not it's much easier like this:
function getDynamicProp($string, $property) {
$string = str_replace(array(':',';'), array('=','&'), $string);
parse_str($string, $result);
return $result[$property];
}
Or store them as cheese=no&sauce=yes&chicken=brown. Then it's even easier still.

PHP foreach overwrite value with array

I'm making a simple PHP Template system but I'm getting an error I cannot solve, the thing is the layout loads excellent but many times, can't figure how to solve, here my code
Class Template {
private $var = array();
public function assign($key, $value) {
$this->vars[$key] = $value;
}
public function render($template_name) {
$path = $template_name.'.tpl';
if (file_exists($path)) {
$content = file_get_contents($path);
foreach($this->vars as $display) {
$newcontent = str_replace(array_keys($this->vars, $display), $display, $content);
echo $newcontent;
}
} else {
exit('<h1>Load error</h1>');
}
}
}
And the output is
Title is : Welcome to my template system
Credits to [credits]
Title is : [title]
Credits to Credits to Alvaritos
As you can see this is wrong, but don't know how to solve it.
You're better off with strtr:
$content = file_get_contents($path);
$new = strtr($content, $this->vars);
print $new;
str_replace() does the replaces in the order the keys are defined. If you have variables like array('a' => 1, 'aa' => 2) and a string like aa, you will get 11 instead of 2. strtr() will order the keys by length before replacing (highest first), so that won't happen.
Use this:
foreach($this->vars as $key => $value)
$content = str_replace($key,$value,$content);
echo $content;

Parse Wordpress like Shortcode

I want to parse shortcode like Wordpress with attributes:
Input:
[include file="header.html"]
I need output as array, function name "include" and attributes with values as well , any help will be appreciated.
Thanks
Here's a utility class that we used on our project
It will match all shortcodes in a string (including html) and it will output an associative array including their name, attributes and content
final class Parser {
// Regex101 reference: https://regex101.com/r/pJ7lO1
const SHORTOCODE_REGEXP = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\#\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u";
// Regex101 reference: https://regex101.com/r/sZ7wP0
const ATTRIBUTE_REGEXP = "/(?<name>\\S+)=[\"']?(?P<value>(?:.(?![\"']?\\s+(?:\\S+)=|[>\"']))+.)[\"']?/u";
public static function parse_shortcodes($text) {
preg_match_all(self::SHORTOCODE_REGEXP, $text, $matches, PREG_SET_ORDER);
$shortcodes = array();
foreach ($matches as $i => $value) {
$shortcodes[$i]['shortcode'] = $value['shortcode'];
$shortcodes[$i]['name'] = $value['name'];
if (isset($value['attrs'])) {
$attrs = self::parse_attrs($value['attrs']);
$shortcodes[$i]['attrs'] = $attrs;
}
if (isset($value['content'])) {
$shortcodes[$i]['content'] = $value['content'];
}
}
return $shortcodes;
}
private static function parse_attrs($attrs) {
preg_match_all(self::ATTRIBUTE_REGEXP, $attrs, $matches, PREG_SET_ORDER);
$attributes = array();
foreach ($matches as $i => $value) {
$key = $value['name'];
$attributes[$i][$key] = $value['value'];
}
return $attributes;
}
}
print_r(Parser::parse_shortcodes('[include file="header.html"]'));
Output:
Array
(
[0] => Array
(
[shortcode] => [include file="header.html"]
[name] => include
[attrs] => Array
(
[0] => Array
(
[file] => header.html
)
)
)
)
Using this function
$code = '[include file="header.html"]';
$innerCode = GetBetween($code, '[', ']');
$innerCodeParts = explode(' ', $innerCode);
$command = $innerCodeParts[0];
$attributeAndValue = $innerCodeParts[1];
$attributeParts = explode('=', $attributeAndValue);
$attribute = $attributeParts[0];
$attributeValue = str_replace('"', '', $attributeParts[1]);
echo $command . ' ' . $attribute . '=' . $attributeValue;
//this will result in include file=header.html
$command will be "include"
$attribute will be "file"
$attributeValue will be "header.html"
I also needed this functionality in my PHP framework. This is what I've written, it works pretty well. It works with anonymous functions, which I really like (it's a bit like the callback functions in JavaScript).
<?php
//The content which should be parsed
$content = '<p>Hello, my name is John an my age is [calc-age day="4" month="10" year="1991"].</p>';
$content .= '<p>Hello, my name is Carol an my age is [calc-age day="26" month="11" year="1996"].</p>';
//The array with all the shortcode handlers. This is just a regular associative array with anonymous functions as values. A very cool new feature in PHP, just like callbacks in JavaScript or delegates in C#.
$shortcodes = array(
"calc-age" => function($data){
$content = "";
//Calculate the age
if(isset($data["day"], $data["month"], $data["year"])){
$age = date("Y") - $data["year"];
if(date("m") < $data["month"]){
$age--;
}
if(date("m") == $data["month"] && date("d") < $data["day"]){
$age--;
}
$content = $age;
}
return $content;
}
);
//http://stackoverflow.com/questions/18196159/regex-extract-variables-from-shortcode
function handleShortcodes($content, $shortcodes){
//Loop through all shortcodes
foreach($shortcodes as $key => $function){
$dat = array();
preg_match_all("/\[".$key." (.+?)\]/", $content, $dat);
if(count($dat) > 0 && $dat[0] != array() && isset($dat[1])){
$i = 0;
$actual_string = $dat[0];
foreach($dat[1] as $temp){
$temp = explode(" ", $temp);
$params = array();
foreach ($temp as $d){
list($opt, $val) = explode("=", $d);
$params[$opt] = trim($val, '"');
}
$content = str_replace($actual_string[$i], $function($params), $content);
$i++;
}
}
}
return $content;
}
echo handleShortcodes($content, $shortcodes);
?>
The result:
Hello, my name is John an my age is 22.
Hello, my name is Carol an my age is 17.
This is actually tougher than it might appear on the surface. Andrew's answer works, but begins to break down if square brackets appear in the source text [like this, for example]. WordPress works by pre-registering a list of valid shortcodes, and only acting on text inside brackets if it matches one of these predefined values. That way it doesn't mangle any regular text that might just happen to have a set of square brackets in it.
The actual source code of the WordPress shortcode engine is fairly robust, and it doesn't look like it would be all that tough to modify the file to run by itself -- then you could use that in your application to handle the tough work. (If you're interested, take a look at get_shortcode_regex() in that file to see just how hairy the proper solution to this problem can actually get.)
A very rough implementation of your question using the WP shortcodes.php would look something like:
// Define the shortcode
function inlude_shortcode_func($attrs) {
$data = shortcode_atts(array(
'file' => 'default'
), $attrs);
return "Including File: {$data['file']}";
}
add_shortcode('include', 'inlude_shortcode_func');
// And then run your page content through the filter
echo do_shortcode('This is a document with [include file="header.html"] included!');
Again, not tested at all, but it's not a very hard API to use.
I have modified above function with wordpress function
function extractThis($short_code_string) {
$shortocode_regexp = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\#\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u";
preg_match_all($shortocode_regexp, $short_code_string, $matches, PREG_SET_ORDER);
$shortcodes = array();
foreach ($matches as $i => $value) {
$shortcodes[$i]['shortcode'] = $value['shortcode'];
$shortcodes[$i]['name'] = $value['name'];
if (isset($value['attrs'])) {
$attrs = shortcode_parse_atts($value['attrs']);
$shortcodes[$i]['attrs'] = $attrs;
}
if (isset($value['content'])) {
$shortcodes[$i]['content'] = $value['content'];
}
}
return $shortcodes;
}
I think this one help for all :)
Updating the #Duco's snippet, As it seems like, it's exploding by spaces which ruins when we have some like
[Image source="myimage.jpg" alt="My Image"]
To current one:
function handleShortcodes($content, $shortcodes){
function read_attr($attr) {
$atList = [];
if (preg_match_all('/\s*(?:([a-z0-9-]+)\s*=\s*"([^"]*)")|(?:\s+([a-z0-9-]+)(?=\s*|>|\s+[a..z0-9]+))/i', $attr, $m)) {
for ($i = 0; $i < count($m[0]); $i++) {
if ($m[3][$i])
$atList[$m[3][$i]] = null;
else
$atList[$m[1][$i]] = $m[2][$i];
}
}
return $atList;
}
//Loop through all shortcodes
foreach($shortcodes as $key => $function){
$dat = array();
preg_match_all("/\[".$key."(.*?)\]/", $content, $dat);
if(count($dat) > 0 && $dat[0] != array() && isset($dat[1])){
$i = 0;
$actual_string = $dat[0];
foreach($dat[1] as $temp){
$params = read_attr($temp);
$content = str_replace($actual_string[$i], $function($params), $content);
$i++;
}
}
}
return $content;
}
$content = '[image source="one" alt="one two"]';
Result:
array(
[source] => myimage.jpg,
[alt] => My Image
)
Updated (Feb 11, 2020)
It appears to be following regex under preg_match only identifies shortcode with attributes
preg_match_all("/\[".$key." (.+?)\]/", $content, $dat);
to make it work with as normal [contact-form] or [mynotes]. We can change the following to
preg_match_all("/\[".$key."(.*?)\]/", $content, $dat);
I just had the same problem. For what I have to do, I am going to take advantage of existing xml parsers instead of writing my own regex. I am sure there are cases where it won't work
example.php
<?php
$file_content = '[include file="header.html"]';
// convert the string into xml
$xml = str_replace("[", "<", str_replace("]", "/>", $file_content));
$doc = new SimpleXMLElement($xml);
echo "name: " . $doc->getName() . "\n";
foreach($doc->attributes() as $key => $value) {
echo "$key: $value\n";
}
$ php example.php
name: include
file: header.html
to make it work on ubuntu I think you have to do this
sudo apt-get install php-xml
(thanks https://drupal.stackexchange.com/a/218271)
If you have lots of these strings in a file, then I think you can still do the find replace, and then just treat it all like xml.

Complex? Eplode() variable I can't figure out

I have a variable, let's call it $var that echoes out something like:
32-Widgets: 18,28-Widgets: 24,57-Widgets: 45,44-Widgets: 24,55-Widgets: 45
The variable is created from a combination of a form submission and jQuery Sortables (which is why everything ends up in one variable, not two). The order is very important.
What I'd like to end up with is two variables (can be arrays) that would be:
$newVar1 = 32,18,24,45,24
$newVar2 = Widgets: 18,Widgets: 24,Widgets: 45,Widgets: 24,Widgets: 45
I started by:
$newVars = explode(",",$var);
But I'm at a loss of where to go from there. I've tried a variety of statements such as:
foreach ($newVars as $newVar) :
//Various explode() functions tried here.
endforeach;
If anybody has any idea what I'm missing I would certainly appreciate the help.
Thank you,
Eric
It's not very pretty, but it'll do the trick.
<?php
$str = "32-Widgets: 18,28-Widgets: 24,57-Widgets: 45,44-Widgets: 24,55-Widgets: 45";
$entries = explode(",", $str);
$parts1 = array();
$parts2 = array();
foreach ($entries as $e)
{
$temp = explode("-", $e);
$parts1[] = $temp[0];
$parts2[] = $temp[1];
}
print_r($parts1);
print_r($parts2);
?>
Running example: http://ideone.com/KkL06f
Have you tried something like this:
public function just_a_test() {
$var = "32-Widgets: 18,28-Widgets: 24,57-Widgets: 45,44-Widgets: 24,55-Widgets: 45";
$vars = explode(',', $var);
$partsA = $partsB = array();
foreach ($vars as $aVar) {
preg_match('/^(\d+)-(Widgets: \d+)$/i', $aVar, $parts);
$partsA []= $parts[0];
$partsB []= $parts[1];
}
echo '<pre>';
print_r($partsA);
print_r($partsB);
echo '</pre>';
}
You could easily end up with output like yours by calling the implode() with each array.

Convert a String to Variable

I've got a multidimensional associative array which includes an elements like
$data["status"]
$data["response"]["url"]
$data["entry"]["0"]["text"]
I've got a strings like:
$string = 'data["status"]';
$string = 'data["response"]["url"]';
$string = 'data["entry"]["0"]["text"]';
How can I convert the strings into a variable to access the proper array element? This method will need to work across any array at any of the dimensions.
PHP's variable variables will help you out here. You can use them by prefixing the variable with another dollar sign:
$foo = "Hello, world!";
$bar = "foo";
echo $$bar; // outputs "Hello, world!"
Quick and dirty:
echo eval('return $'. $string . ';');
Of course the input string would need to be be sanitized first.
If you don't like quick and dirty... then this will work too and it doesn't require eval which makes even me cringe.
It does, however, make assumptions about the string format:
<?php
$data['response'] = array(
'url' => 'http://www.testing.com'
);
function extract_data($string) {
global $data;
$found_matches = preg_match_all('/\[\"([a-z]+)\"\]/', $string, $matches);
if (!$found_matches) {
return null;
}
$current_data = $data;
foreach ($matches[1] as $name) {
if (key_exists($name, $current_data)) {
$current_data = $current_data[$name];
} else {
return null;
}
}
return $current_data;
}
echo extract_data('data["response"]["url"]');
?>
This can be done in a much simpler way. All you have to do is think about what function PHP provides that creates variables.
$string = 'myvariable';
extract(array($string => $string));
echo $myvariable;
done!
You can also use curly braces (complex variable notation) to do some tricks:
$h = 'Happy';
$n = 'New';
$y = 'Year';
$wish = ${$h.$n.$y};
echo $wish;
Found this on the Variable variables page:
function VariableArray($data, $string) {
preg_match_all('/\[([^\]]*)\]/', $string, $arr_matches, PREG_PATTERN_ORDER);
$return = $arr;
foreach($arr_matches[1] as $dimension) { $return = $return[$dimension]; }
return $return;
}
I was struggling with that as well,
I had this :
$user = array('a'=>'alber', 'b'=>'brad'...);
$array_name = 'user';
and I was wondering how to get into albert.
at first I tried
$value_for_a = $$array_name['a']; // this dosen't work
then
eval('return $'.$array_name['a'].';'); // this dosen't work, maybe the hoster block eval which is very common
then finally I tried the stupid thing:
$array_temp=$$array_name;
$value_for_a = $array_temp['a'];
and this just worked Perfect!
wisdom, do it simple do it stupid.
I hope this answers your question
You would access them like:
print $$string;
You can pass by reference with the operator &. So in your example you'll have something like this
$string = &$data["status"];
$string = &$data["response"]["url"];
$string = &$data["entry"]["0"]["text"];
Otherwise you need to do something like this:
$titular = array();
for ($r = 1; $r < $rooms + 1; $r ++)
{
$title = "titular_title_$r";
$firstName = "titular_firstName_$r";
$lastName = "titular_lastName_$r";
$phone = "titular_phone_$r";
$email = "titular_email_$r";
$bedType = "bedType_$r";
$smoker = "smoker_$r";
$titular[] = array(
"title" => $$title,
"first_name" => $$firstName,
"last_name" => $$lastName,
"phone" => $$phone,
"email" => $$email,
"bedType" => $$bedType,
"smoker" => $$smoker
);
}
There are native PHP function for this:
use http://php.net/manual/ru/function.parse-str.php (parse_str()).
don't forget to clean up the string from '"' before parsing.
Perhaps this option is also suitable:
$data["entry"]["0"]["text"];
$string = 'data["entry"]["0"]["text"]';
function getIn($arr, $params)
{
if(!is_array($arr)) {
return null;
}
if (array_key_exists($params[0], $arr) && count($params) > 1) {
$bf = $params[0];
array_shift($params);
return getIn($arr[$bf], $params);
} elseif (array_key_exists($params[0], $arr) && count($params) == 1) {
return $arr[$params[0]];
} else {
return null;
}
}
preg_match_all('/(?:(\w{1,}|\d))/', $string, $arr_matches, PREG_PATTERN_ORDER);
array_shift($arr_matches[0]);
print_r(getIn($data, $arr_matches[0]));
P.s. it's work for me.

Categories