run php script from database record without using eval() - php

I would like to know how to run the php scripts which are stored in the database without using eval().
The expected process is as follow
When user POST a string which contains {{typed_alias }}, the system will search the table whether this alias has record in the alias column.
If yes -> replace what user typed with the correspond script which is stored in the replacement column.
If not -> show the original string including {{ wrong_alias }}
The expected result is as follow
When user posts
Hello, {{morninggg}}, the current unix time is {{nowTime}}
Array output from db
array
0 =>
array
'ID' => 445
'alias' => 'morning'
'replacement' => 'Good morning'
1 =>
array
'ID' => 446
'alias' => 'nowTime'
'replacement' => time()
2 =>
array
'ID' => 447
'alias' => 'tommorowNow'
'replacement' => time()+86400
Return
Hello, {{morninggg}}, the current unix time is 147855220
Now I have already solved the database array by using foreach and also can replace the alias with script by using str_replace().
Current classI use to foreach data from database and do the replacement is as follow
class replace {
public $definitions;
public function setDefinitions($definitions) {
$this->definitions = $definitions;
}
public function tag($input) {
if($this->definitions && is_array($this->definitions)) {
foreach ($this->definitions as $definition) {
if($defintion['alias'] == 'time') {
$input = str_replace('{{' . $definition['alias'] . '}}', date('Y-m-d'), $input);
} else {
$input = str_replace('{{' . $definition['alias'] . '}}', $definition['replacement'], $input);
}
}
}
return $input;
}
}
Current using method
$replace = new replace();
$replace->setDefinitions($tagEngine);
$parsedString = $replace->tag($__input);
//$__input is what user POST to the server
echo $parsedString;
However, the current result is as follow
Hello, {{morninggg}}, the current unix time is time()
The script can't be run successfully on the page
But when I give the definition manually like this
$definition = array('morning' => 'Good Morning', 'nowTime' => time());
foreach ($definition as $key => $value)
$source = str_replace('{{' . $key . '}}', $value, $source);
return $source;
The script can be run and returns
Hello, {{morninggg}}, the current unix time is 147855220
I know that using eval() can run the scripts, however, it is regarded as a dangerous method in a real-world application by people.
Can anyone give me suggestions about how to deal with this problem?
Thank you!

You should not use functions like eval() to fix this. You should pull all php-code out of your database and parse the different aliasses as follows (I have just altered the tag() method in the replace class:
public function tag($input) {
if($this->definitions && is_array($this->definitions)) {
foreach ($this->definitions as $definition) {
$replacement = $definition['replacement'];
switch($definition['alias']) {
case 'nowTime':
$replacement = date('Y-m-d');
break;
case 'tommorowNow':
$replacement = date('Y-m-d', (time() + 86400));
break;
}
$input = str_replace('{{' . $definition['alias'] . '}}', $replacement, $input);
}
}
return $input;
}
As you can see, for every php-code alias, you can add another case in the switch() statement. You can read up on the switch() control structures at the following link:
PHP: switch - Manual

Related

Is there a way to dynamically access multidimensional PHP array?

Is there a way to access a PHP multidimensional array (specific index) dynamically?
So for example, say I want to access a value at:
$array[1]['children'][0]['children'][2]['settings']['price']
Can there be a function which returns this value by just getting index (1, 0 and 2 respectively)? and in a way that it works whether there are 3 values (1, 0 and 2) or more.
SO for example , we call function "getArrayValue()" and we can it like so:
getArrayValue('1,0,2')
this should return
$array[1]['children'][0]['children'][2]['country']['city']
or in case of 2 values
getArrayValue('1,0')
should return
$array[1]['children'][0]['country']['city']
so basically, the issue I am facing is needing help with dynamically building the query to get array value...
Or if there is a way to convert a string like $array[1]['children'][0]['country']['city'] and evaluate it to get this value from the array itself?
Another way to explain my problem:
$arrayIndex = "[1]['children'][0]";
$requiredValue = $array[1] . $arrayIndex . ['country']['city'];
//// so $requiredValue should output the same value as the below line would:
$array[1]['children'][0]['children'][2]['country']['city'];
Is there a way to achieve this?
In your case you will need something like this:
<?php
function getArray($i, $j, $k, $array) {
if (isset($array[$i]['children'][$j]['children'][$k]['country']['city']))
{
return $array[$i]['children'][$j]['children'][$k]['country']['city'];
}
}
$array[0]['children'][0]['children'][0]['country']['city'] = "some value";
$array[0]['children'][0]['children'][1]['country']['city'] = "another";
$array[0]['children'][1]['children'][1]['country']['city'] = "another one";
.
.
.
etc
echo getArray(0,0,0, $array) . "\n"; // output -> "some value"
echo getArray(0,0,1, $array) . "\n"; // output -> "another"
echo getArray(0,1,1, $array) . "\n"; // output -> "another one"
Another thing to keep in mind is that you have called the function passing only one parameter. And your multidimensional array needs at least three.
getArrayValue('1,0,2')
You have to take into account that you have called the function passing only one parameter. Even if there were commas. But it's actually a string.
getArrayValue(1,0,2) //not getArrayValue('1,0,2') == string 1,0,2
If you want to pass two values, you would have to put at least one if to control what you want the function to execute in that case. Something like:
function getArray($i, $j, $k, $array) {
if($k==null){
if(isset($array[$i]['children'][$j]['country']['city'])){
return $array[$i]['children'][$j]['country']['city']; //
}
} else {
if(isset($array[%i]['children'][$j]['children'][$k]['country']['city'])){
return $array[$i]['children'][$j]['children'][$k]['country']['city'];
}
}
}
getArray(0,0,null, $array)
getArray(0,0,1, $array)
For the last question you can get by using the eval() function. But I think it's not a very good idea. At least not recommended. Example:
echo ' someString ' . eval( 'echo $var = 15;' );
You can see the documentation: https://www.php.net/manual/es/function.eval.php
edit:
I forgot to mention that you can also use default arguments. Like here.
<?php
$array[0]['children'][0]['children'][0]['country']['city'] = "some value";
$array[0]['children'][0]['children'][1]['country']['city'] = "another";
$array[0]['children'][1]['children'][1]['country']['city'] = "another one";
function getArray($array,$i, $j, $k = null) {
if($k==null){
echo 'getArray called without $k argument';
echo "\n";
}
else{
echo 'getArray called with $k argument';
echo "\n";
}
}
getArray($array,0,0); //here you call the function with only 3 arguments, instead of 4
getArray($array,0,0,1);
In that case $k is optional. If you omit it, the default value will be null. Also you have to take into account that A function may define default values for arguments using syntax similar to assigning a variable. The default is used only when the parameter is not specified; in particular, note that passing null does not assign the default value.
<?php
function makecoffee($type = "cappuccino"){
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
The above example will output:
Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.
You can read more about that here: https://www.php.net/manual/en/functions.arguments.php
I find #Dac2020's answer to be too inflexible to be helpful to future researchers. In fact, the overly specific/niche requirements in the question does not lend this page to being very helpful for future researchers because the processing logic is tightly coupled to the array structure.
That said, I've tried to craft a function that builds best practices of checking for the existence of keys and D.R.Y. principles in the hope that future researchers will be able to easily modify it for their needs.
Inside the custom function, the first step is to split the csv into an array then interweave the static keys between the dynamic keys as dictated by the asker. In more general use cases, ALL keys would be passed into the function thus eliminating the need to prepare the array of keys.
As correctly mentioned by #MarkusAO in a comment under the question, this question is nearly a duplicate of Convert dot syntax like "this.that.other" to multi-dimensional array in PHP.
Code: (Demo)
function getValue($haystack, $indexes) {
$indices = explode(',', $indexes);
$finalIndex = array_pop($indices);
$keys = [];
foreach ($indices as $keys[]) {
$keys[] = 'children';
}
array_push($keys, $finalIndex, 'country', 'city');
//var_export($keys);
foreach ($keys as $level => $key) {
if (!key_exists($key, $haystack)) {
throw new Exception(
sprintf(
"Path attempt failed for [%s]. No `%s` key found on levelIndex %d",
implode('][', $keys),
$key,
$level
)
);
}
$haystack = $haystack[$key];
}
return $haystack;
}
$test = [
[
'children' => [
[
'children' => [
[
'country' => [
'city' => 'Paris',
]
],
[
'country' => [
'city' => 'Kyiv',
]
]
]
]
]
],
[
'children' => [
[
'country' => [
'city' => 'New York',
]
],
[
'country' => [
'city' => 'Sydney',
]
]
]
]
];
$result = [];
try {
$result['0,0,0'] = getValue($test, '0,0,0');
$result['1,0'] = getValue($test, '1,0');
$result['1,0,0'] = getValue($test, '1,0,0');
} catch (Exception $e) {
echo $e->getMessage() . "\n---\n";
}
var_export($result);
Output:
Path attempt failed for [1][children][0][children][0][country][city]. No `children` key found on levelIndex 3
---
array (
'0,0,0' => 'Paris',
'1,0' => 'New York',
)

using array_search or loop in PHP to find the position of a key

I wrote this code to find domain names in an array in PHP. My question is how to find the position of the key without using a loop.
I wrote both forms to show my meaning.
<?php
$unique_domains = array( "www.crownworldwide.com","www.acquisition.gov", "www.hemisphere-freight.com",
"www.businessinsider.com","www.oceansidelogistics.com","mixjet.aero","www.airindiaexpress.in", "rlglobal.com",
"www.metroshipping.co.uk","www.flexport.com"
);
$position = array_search("flexport.com",$unique_domains);
echo "position is ". $position . "<br>";
<----------------------------------------->
$position2 = 0 ;
foreach ($unique_domains as $key ) {
$position2++;
if(preg_match('/'.preg_quote("flexport.com").'\b/',$key)){
echo "position is ".$position2 ;
}
}
?>
On the first method I was not able to find the position as it has www. at the beginning. On the second method I can find the position but I do not want to use a loop in my live platform. What are the alternative to find the domain names inside an array?
Update:
Also the result must be domain specific and all subdomains must be accepted.
For example:
flexport.com :
flexport.co - is wrong
app.flexport.co is correct
Another way is to use preg_match() and a simple foreach. This method avoid the iteration of all items of the array and stops when a match is found.
/**
* Returns the index of the first match or false if not found.
*/
function arraySearch(array $array, string $search): int|false
{
foreach ($array as $key => $value) {
if (preg_match('~' . $search . '$~',$value)) {
return $key;
}
}
return false;
}
$unique_domains = [
'www.crownworldwide.com',
'www.acquisition.gov',
'www.hemisphere-freight.com',
'www.businessinsider.com',
'www.oceansidelogistics.com',
'mixjet.aero',
'www.airindiaexpress.in',
'rlglobal.com',
'www.metroshipping.co.uk',
'www.flexport.com'
];
var_dump(arraySearch($unique_domains, 'flexport.co')); // bool(false)
var_dump(arraySearch($unique_domains, 'flexport.com')); // int(9)
live demo PHP 8.0
live demo PHP 7.4
$unique_domains = [
'www.crownworldwide.com',
'www.acquisition.gov',
'www.hemisphere-freight.com',
'www.businessinsider.com',
'www.oceansidelogistics.com',
'mixjet.aero',
'www.airindiaexpress.in',
'rlglobal.com',
'www.metroshipping.co.uk',
'www.flexport.com'
];
$position = array_key_first(array_filter($unique_domains, fn($val) => str_contains($val, 'flexport.com')));
echo 'position is ' . $position;
$input = preg_quote('flexport.com', '~'); // don't forget to quote input string!
$data = array("www.crownworldwide.com","www.acquisition.gov", "www.hemisphere-freight.com",
"www.businessinsider.com","www.oceansidelogistics.com","mixjet.aero","www.airindiaexpress.in", "rlglobal.com",
"www.metroshipping.co.uk","www.flexport.com");
$result = preg_grep('~' . $input . '~', $data);
var_dump($result); // array(1) { [9]=> string(16) "www.flexport.com" }
array_keys($result); // [9]
Update 2.0
I think we should take a simple and pragmatic approach here. The goal is to only get the index of an array if the search domain matches. Regardless of whether with www. or without.
A function that accepts a search string. Remove the www. in the search string as well as the values of the array. This way you compare domain with domain. and you only get unique results. Then return the key. that's it!
<?php
function position($search) {
$unique_domains = [
'www.crownworldwide.com',
'www.acquisition.gov',
'www.hemisphere-freight.com',
'www.businessinsider.com',
'www.oceansidelogistics.com',
'mixjet.aero',
'www.airindiaexpress.in',
'rlglobal.com',
'www.metroshipping.co.uk',
'www.flexport.com'
];
foreach($unique_domains as $k => $v)
{
$plain_1 = str_replace("www.","",$v);
$plain_2 = str_replace("www.","",$search);
if($plain_1 == $plain_2) {
return $k;
}
}
return false;
}
print_r('flexport.com => ' .position('flexport.com')); // 9
echo '<br/>';
print_r('www.flexport.com => ' . position('www.flexport.com')); // 9
echo '<br/>';
print_r('om' . position('om')); // 0
**working example (updated 2.0) **
https://3v4l.org/B4TAu#v8.1.2

Function in array executed before calling it

I have an array like this:
$cmds = array(
'info' => call_user_func('_info', $cmd1),
'e1' => 'something'
);
The func itself:
function _info($cmd1){
if(strlen($cmd1) < 2){
die('Invalid Username');
}else{
echo 'cmd1 > 2';}
}
The problem is it being executed before i call it giving undefined variable error because $cmd1 not exist yet, it will be exist when i call it in a foreach function.
Been searching for a solution for hours but didn't find.
I tried setting the array as this 'info' => _info($cmd1) and 'info' => '_info' and putted $cmd1 directly in the func like this
function _info(){
if(strlen($cmd1) < 2){die('invalid');
}
But i still get the same error as it being called before i want to be.
You can send parameters to be executed later
$cmds = array(
'info' => [ '_info', '$cmd1' ], // single quotes
'e1' => 'something'
);
In the meantime your cmd1 is defined
$cmd1 = "hello";
foreach ($cmds as $key => $cmdset) {
if (!is_array($cmdset)) {
// do something with e1 => something
} else {
$function = array_shift($cmdset);
foreach ($cmdset as &$param) {
// Only variables are treated below, values are passed through as is
if (stripos($param, '$') === 0) {
// Remove $
$cmd1 = substr($param, 1);
// Set param to the value of cmd1
$param = $$param; // variable varaible $$
}
}
call_user_func_array($function, $cmdset);
}
}
While this works it is really bad practice to do like this. Depending on a variable function that is not clear if it is set or not. The code is hard to understand.
You should think about another solution where you can ensure that $cmd1 is set or can be retrieved and if it is not have some way to deal with that as well.

check if a word in string match with a key in array, then replace it

i want to find a keyword inside a string, im trying to make the script to find it and then replace it, but only that keyword (of course if others are found, replace them as well). but im lack of experience for this job and im trying to do it just for practice. this is my beginning code:
$var = array(
'{test1}' => 'something1',
'{test2}' => 'something2',
'{test3}' => 'something3'
);
$output = 'Please work it var {test1}!';
foreach($var as $element)
{
if(strstr($output, $element) !== false)
{
echo 'not found<br>';
}
else
{
echo 'found<br>';
}
}
for now im just checking if its found, but what i dont understand, why its repeating? it should just say "found" once and then say "not found", like this (found, not found, not found).
output:
found
found
found
This is a little confusing for me, as strstr is usually used to grab a portion of the string. I think a more appropriate approach would be using strpos. also you're not testing the key. don't even know why it's saying found. try
foreach($var as $key=>$val)
{
if(strpos($output, $key) !== false)
{
//the key is contained in the output.
}
else
{
//not found
}
}
if you let us know what you're trying to replace, I can see about helping with that. Also don't listen to everyone telling you to use == to compare against false. === or !== is the appropriate comparison as there are other things that == false(ie.. 0 ==false).
Realistically though, if you're trying to just replace the key of your array with the value, there is no need for a check.
foreach($var as $key=>$val)
$output = str_replace($key, $value, $output);
if the key is not found, nothing happens, if it is, it's replaced with its corresponding value. No check necessary.
First of all you have your if statement wrong. It is not finding it 3 times, that's why it is repeating (3 times for each item in your array):
if(strstr($output, $element) == false)
Remove the !. What you are saying is, if a match is found then echo "not found".
That is one problem, the second is that your code will not work. You are looking for the values of your array, rather than the keys. Try this:
$var = array(
'{test1}' => 'something1',
'{test2}' => 'something2',
'{test3}' => 'something3'
);
$output = 'Please work it var {test1}!';
foreach($var as $search => $replace)
{
if(strstr($output, $search) == false)
{
echo 'not found<br>';
}
else
{
echo 'found<br>';
}
}
The difference here is that you can access the array keys and values in the foreach buy using foreach (array_expression as $key => $value). I named the array keys $search since that is what you are looking for. Then you can access the array value using $replace to replace the string once found like so:
$var = array(
'{test1}' => 'something1',
'{test2}' => 'something2',
'{test3}' => 'something3'
);
$output = 'Please work it var {test1}!';
foreach($var as $search => $replace)
{
if(strstr($output, $search) == false)
{
echo 'not found<br>';
}
else
{
echo 'found - (' . str_replace($search, $replace, $output) . ')<br>';
}
}

php function with arrays

I want to pass one argument to a function, rather than multiple arguments, that tend to grow unexpectedly. So I figure an array will get the job done. Here's what I've drafted so far...
<?php
function fun_stuff($var){
// I want to parse the array in the function, and use
}
$my = array();
$my['recordID'] = 5;
$my['name'] = 'John Smith';
$my['email'] = 'john#someemail.com';
echo fun_stuff($my);
?>
I haven't quite grasped the concept of parsing an array. And this is a good way for me to learn. I generally pass the same variables, but on occasion a record does not have an email address, so I do need to make a condition for missing keys.
Am I doing this right so far? Can I pass an array as an argument to a function?
And if so, how do I parse and search for existing keys?
Hopefully this isn't too far off topic...but you sounded like you were just trying to avoid multiple parameters when some can be NULL. So, I would recommend that you use an object instead of an array for clarity...that way, there is no confusion as to what properties should exist. If you're using PHP 5, you can also strongly type the parameter so nothing else can get in. So:
class Record {
public $Id;
public $Name;
public $Email
}
function fun_stuff( Record $record ) {
// you will now have better intellisense if you use an IDE
// and other develoers will be able to see intended parameters
// clearly, while an array would require them to know what's
// intended to be there.
if( !empty($record->Email) ) {
// do whatever.
}
}
Yes you are on the right track. The approach I take is put required paramters as the first parameters and all optional parameters in the last argument which is an array.
For example:
function fun_stuff($required1, $required2, $var = array()) {
// parse optional arguments
$recordId = (key_exists('recordID', $var) ? $var['recordId'] : 'default value');
$name = (key_exists('name', $var) ? $var['name'] : 'default value');
$email = (key_exists('email', $var) ? $var['email'] : 'default value');
}
Then you can call your function like so:
fun_stuff('val 1', 'val 2', array(
'recordId' => 1,
'name' => 'John',
'email' => 'john#stackoverflow.com'
));
This is a bad design practice, but that's not the question here. You can "parse" array's like so...
if( array_key_exists( 'email', $var ))
{
// use email field
}
If you need to, you can loop through all elements like so...
foreach( $var as $key => $value )
{
echo '$var[\''.$key.'\'] = '.$value;
}
I'm not recommend you to use array for this.
You can define optional arguments with default values:
//$name and $email are optional here
function fun($record_id, $name='', $email='')
{
if (empty($name)) print '$name is empty';
}
//Usage:
fun(5, 'Robert');
fun(5);
fun(5, 'Robert', 'robert#gmail');
fun(3,'','robert#gmail');
If you will use array, IDE will not be able to show autocomplete suggestions, it means more typos, and you have to remember all keys of this array forever or look at code of the function each time.
I'm not really sure what you want to achieve, but I suspect something like this:
$aPersons = array();
$aPersons[] = array('name' => 'name1', 'age' => 1);
$aPersons[] = array('name' => 'name2', 'age' => 2);
array_map('parsePerson', $aPersons);
function parsePerson($aPerson) {
echo $aPerson['name'];
echo $aPerson['age'];
}
The problem with your current array is that it only has one dimension.
You can simple do echo $my['name'];. There are easier ways to parse arrays though.
foreach($aPersons as $aPerson) {
echo $aPerson['name'];
echo $aPerson['age'];
}
$iLength = sizeof($aPersons);
for($i = 0; $i <= $iLength; $i++) {
echo $aPersons[$i]['name'];
echo $aPersons[$i]['age'];
}
To parse and view, there is the signficant print_r function which gives out the array details.
When calling a function you need the return syntax at the end that will parse out anything you call in the return.
You obviously can pass array to the function. Inside it read the variable as you were assigning values before it. If you assign:
$my['key'] = 'value';
In you function use:
echo $var['key'];
Why you don't use a foreach to walk in array?
function fun_stuff($var){
foreach($var as $key => $item){
echo '[', $key, "] => ", $item, "\n";
}
}
$my = array();
$my['recordID'] = 5;
$my['name'] = 'John Smith';
$my['email'] = 'john#someemail.com';
fun_stuff($my);
Yes, this is correct (though your question is a bit broad). You're already referencing the array values via indexes when you set up the $my variable. You can do the same thing within your function (with the $var variable).
I recommend taking a look at all of PHP's built-in array functions: http://php.net/manual/en/ref.array.php
Try this:
function fun_stuff($var){
// I want to parse the array in the function, and use
$fun_string = "";
if( is_array( $var ) {
if( array_key_exists( "name", $var ) )
$fun_string .= "For " . $var["name"];
else $fun_string .= "A nameless one ";
if( array_key_exists( "email", $var ) )
$fun_string .= " (email: " . $var["email"] . ")";
else $fun_string .= " without a known e-mail address";
if( array_key_exists( "recordID", $var ) )
$fun_string .= " has record ID of " . $var["recordID"];
else $fun_string .= " has no record ID set";
$fun_string .= "\n";
}
return $fun_string;
}
Yes You can! Just pass the array and inside the function just use a foreach loop to parse it!
function myFunction($array)
{
foreach($array as $value)
{
echo $value;
}
}
or If you want to have full control over the pair key/value:
function myFunction($array)
{
foreach($array as $key=>$value)
{
echo "key:".$array[$key]."value:".$values;
}
}

Categories