In creating automatic emails certain parts of the email need to be replaced with stored data.
eg. Dear %first_name% %surname%, Thanks for attending the %place_name%.
This could be done with a string replace for each of them, but there must be a faster method.
Assuming that the variable name is identical to what we want from the system eg. %first_name% should be replaced with $user['first_name'] etc....
You can utilise preg_replace_callback to replace keys between %'s with array values:
$fields = array('first_name' => 'Tim', 'place_name' => 'Canada');
$string = preg_replace_callback('/%(.+?)%/', function($arr) use($fields)
{
$key = $arr[1];
return array_key_exists($key, $fields) ? $fields[$key] : $arr[0];
}, $string);
One option:
$vars = array(
'firstname' = 'Bob',
'surname' = 'Dole',
'place' = 'Las Vegas',
// ...
);
extract($vars);
include('my_template.phtml');
And in my_template.phtml:
<?php
echo <<<EOF
Dear $firstname $surname,<br>
Thank you for attending the Viagra and Plantains Expo in $place.
EOF;
?>
If you're worried about name collisions while using extract(), you can always use the EXTR_PREFIX_ALL option, or one of the other extraction methods.
Or, better yet, don't reinvent the wheel. Just use Smarty or mustache.php.
See also this question: PHP template class with variables?
Related
I'm pretty familiar with the Strtok() function in PHP, and I have had no problem getting the function to work properly for strings in the past. However, I currently have to read a .csv text file (which I've done successfully) where each line is made of 6 fields like so: last name, first name, address, city, district, postal code\r\n <--carriage return and linefeed at the end
I have to use Strok() to split these by the delimiters and token the words as fields (i.e. last, first, address, etc.). I plan to use an associative array using the last name as the primary key so that I can plug the data into an HTML Table, which is created and working. My issue right now is splitting the file correctly, as it has about 200 lines made of those 6 fields, and storing the strings as fields properly for an array, so the data structure is where I'm having some issues. Here's what I have so far:
$inputFile = fopen("input.csv","r");
$delimiters = ",";
$token = strtok($inputFile, $delimiters);
$n=1;
while ($token){
echo "Token $n: $token <br>";
$token = strtok($delimiters);
$n++;
}
Obviously, the table is created below it but since I haven't done the data structure quite yet, I don't have the fields for it. I think my token loop may be incorrect for this issue, but I pulled some from an earlier example in my book and an exercise I did where my token process worked but the file structure was different. Thanks for any direction or help on this.
There are CSV functions in PHP, like fgetcsv, so it really is the wrong approach to reinvent the wheel.
Note that in your code you don't actually read the content of the file, as you only get a file pointer.
If you really need to do this with strtok, and your CSV is simple, in the sense that it does not have quoted strings, which could have embedded delimiter characters, you could use:
file_get_contents() to read the file content in one string. Of course, file() would make it easier for you, as it would already split lines. But I assume that if CSV functions are not allowable for you, then this will neither.
strtok for getting the fields, but at the end of the loop, not at the start, since the initial call with the double arguments already retrieves the first value before the loop.
Code:
$input = file_get_contents("input.csv");
$delimiters = ",\n\r";
$token = strtok($input, $delimiters);
$result = [];
$row = [];
while ($token){
echo "Token $token <br>";
$row[] = $token;
if (count($row) == 6) { // write record
$result[] = $row;
$row = [];
}
$token = str_replace('\r', '', strtok($delimiters));
}
print_r($result);
Note that this does not create an associative array. If you need that, then use this code:
$columns = ['last', 'first', 'address1', 'address2', 'address3', 'zip'];
and then in your loop, replace $row[] = $token by:
$row[$columns[count($row)]] = $token;
You can see that version run on eval.in. The output for the data you provided in comments is:
Array (
[0] => Array (
[last] => SELBY
[first] => AARON
[address1] => 1519 Santiago de los Caballeros Loop
[address2] => Mwene-Ditu
[address3] => East Kasai
[zip] => 22025
)
[1] => Array (
[last] => GOOCH
[first] => ADAM
[address1] => 230 Urawa Drive
[address2] => Adoni
[address3] => Andhra Pradesh
[zip] => 2738
)
)
Again, this is not advisable. You should use fgetcsv. That also deals better with strings that could have commas, double quotes or even newlines in them.
Well, I was going to skip this question because fgetcsv(), but I was bored:
$lines = file($inputFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$delimiters = ",";
foreach($lines as $line) {
$values = array(strtok($line, $delimiters));
while($token = strtok($delimiters)){
$values[] = $token;
}
$result[] = $values;
}
Read the file lines into an array
Loop to get each line and put the first token of the line into a values array
Loop the line and get all tokens and add to values array
Add values array to result array
I added an array_combine() because you said something about an associative array. You can use something like this if needed:
$result[] = array_combine(array('last name',
'first name',
'address',
'city',
'district',
'postal code'), $values);
If you wanted last name to be the key for each result line, which is not advisable as keys are unique and I don't think you can guarantee last names being unique:
$result[$values[0]] = $values;
//or to remove it from the array but use as the key
$result[array_unshift($values)] = $values;
How can I include an string in an array?
emailconfig.php
$globalemail 'info#site.com'=>'site'";
I want to make a new array like this:
sendemail.php
include "emailconfig.php"
$fulllist=array('info#forum.com'=>'forum', '$globalemail');
// the Array MUST must appear above, ideally it would look like this
// $fulllist=array('info#forum.com'=>'forum', 'info#site.com'=>'site');
It brings PHP error because of the =>
One way is: in your emailconfig.php, you should have 2 variables, $globalemailkey and $globalemailvalue.
$globalemailkey = 'info#site.com';
$globalemailvalue = 'site';
$fulllist = array('info#forum.com'=>'forum', $globalemailkey => $globalemailvalue);
Or, store an array in emailconfig.php, and use array_merge.
$globalemail = array('info#site.com' => 'site');
$fulllist = array('info#forum.com'=>'forum');
$fulllist = array_merge($fulllist, $globalemail);
$fulllist=array('info#forum.com'=>'forum');
$globalemail = "info#site.com'=>'site'";
$parts = explode('=>', $globalemail);
$fulllist[trim($parts[0], "'")] = trim($parts[1], "'");
http://ideone.com/mmvu9
You could But You Shouldn't use eval to do something like eval("array($yourstring)");. But you shouldn't. really. please.
You can do all sorts of things like preg-match or explode, but couldn't you easier find the source of those pieces of information, and work from there?
This is a tricky one to explain. I have an associative array which I want to run a set of rules against to return true or false.
I was wondering if there is a library somewhere allowing me to compare a rule (or set of) against an array. Almost like SQL exept I have the record, I just need to see if the SQL would return it or not.
For Example:
$subject = array('name' => 'John Smith', 'age' => '44');
$formula = "name LIKE 'John%' AND (age = 44 OR age = 45)";
if(match($formula, $subject))
return true;
else
return false;
The subject array is NOT from a database it is actually from a form post, otherwise I would just run the SQL and if it returned the correct record then it would be true. Plus this is something that I would like to use a lot with may different associative arrays so adding to a table then running the query to get the same record back will not be possible either. Basically I can't use a database.
You could maybe do something like this?
function match ($subject, $formula) {
extract($subject);
foreach ($formula as $rule) {
if (!eval("return $rule;")) return FALSE;
}
return TRUE;
}
$formula = array(
'substr($name,0,4) == "John"',
'$age == 44 OR $age == 45'
);
$subject1 = array('name' => 'John Smith', 'age' => '44');
$subject2 = array('name' => 'Bob Jones', 'age' => '42');
var_dump(match($subject1, $formula)); // bool (TRUE)
var_dump(match($subject2, $formula)); // bool (FALSE)
This approach means your rules can be as complex as you like; for example, the above $formula can be compressed into this one rule:
$formula = array(
'substr($name,0,4) == "John" AND ($age == 44 OR $age == 45)'
);
Because of the way it works, multiple rules effectively have an AND relationship - as soon as one rule fails, the function returns false.
You can write anything to like, using any PHP function you like, as long as it is a valid comparison expression.
If you want an expression to be parsed as if it were SQL, then use an SQL parser....
$subject = array('name' => 'John Smith', 'age' => '44');
$formula = "'name' LIKE 'John%' AND ('age' = '44' OR 'age' = '45')";
$result=try_expression($subject, $formula);
function try_db_expression($subject, $formula)
{
$keys=array_keys($subject);
$vals=array_values($subject);
foreach ($keys as $k=>$v) {
$keys[$k]='/\b' . mysql_real_escape_string($v) . '\b/i';
}
foreach ($vals as $k=>$v) {
$vals[$k]=mysql_real_escape_string($v);
}
$test=preg_replace($keys, $vals, $subject);
$res=mysql_query("SELECT ($test) AS evald");
if ($r=mysql_fetch_assoc($res)) return $r['evald'];
return false;
}
Basically I can't use a database
Then you'll have to build your own parser (not really - you can use PHP's eval - but you'll need to map the LIKE operator to PHP function).
There are a few implementations like this. You are basically looking for "LINQ in PHP" and one that works against array data sets. PHPLinq
http://devzone.zend.com/1205/linq-for-php-language-integrated-query-for-php/
http://www.switchonthecode.com/tutorials/basic-linq-syntax-in-php-with-phplinq
http://www.phpkode.com./scripts/item/plinq/
There's also one on phpclasses, but I'm not linking there..
Most of them use a more ORM-like query method, not an SQL parser. (Which you could get from http://www.phpinsider.com/php/code/SafeSQL/ or http://pear.php.net/package/SQL_Parser)
You can mimic SQL expressions with a recursive regex. But you cannot as easily parse out and process them with preg_match or _replace_callback. I would not bother unless you really have only such simple examples.
I have a template file that uses the structure
[FIRSTNAME]
[LASTNAME]
etc etc.... and I will be doing a search and replace on it. One thing that I would like to do is that when the template get's sent back, IF I haven't stipulated, [FIRSTNAME].... it still shows in the template... I would like to make it NULL IF I haven't stipulated any data to that variable.
in my code i'm using the FILE_GET_CONTENTS
$q = file_get_contents($filename);
foreach ($this->dataArray as $key => $value)
{
$q = str_replace('['.$key.']', $value, $q);
}
return $q;
So once that loop is over filling in the proper data, I need to do another search and replace for any variables left using, [FIRSTNAME]
I hope this makes sense any someone can steer me in the right direction.
Cheers
It sounds like you just want to add a line like:
$q = preg_replace('/\[[^\]]*\]/', '' , $q);
After all your defined substitutions, to eliminate any remaining square-bracketed words.
If you want to be concise, you can replace the whole function with a variation of the "one line template engine" at http://www.webmasterworld.com/php/3444822.htm, with square brackets instead of curlies.
You can actually pass arrays into the str_replace function as arguments.
$keys = array(
'FIRSTNAME',
'LASTNAME'
):
$replacements = array(
'George',
'Smith'
);
str_replace($keys, $replacements, $input);
And if you want to remove first name if its blank, why don't you just add it to the key => replacement array with a value of ''?
$this->dataArray['FIRSTNAME'] = '';
or something like
if (!isset($this->dataArray['FIRSTNAME'])) {
$this->dataArray['FIRSTNAME'] = '';
}
I want to be access some variables I've assigned dynamically from PHP in Smarty, here is an example:
$content_name = 'body'
$smarty->assign('content_name',$content_name);
$smarty->assign($content_name.'_title',$title);
$smarty->assign($content_name.'_body',$body);
// assigned values
// $content_name = home
// $home_title = $title
// $home_body = $body
The reason I want to access these dynamically is because I call multiple versions of a function that includes the code above, they all use the same template and therefore don't want to simply use $title, $body etc as their valus will conflict with each other.
Given that I know I want to access the title and body variables based on the content_name I set, how can I achieved this within smarty?
Even if this post is very old, the given answere is accpeted but not an answere for the question. Its only an other oppertunity to handle main problem.
The question is how to use dynamic variables...
for the given sample, it should be something like
PHP
$content_name = 'body';
$title = 'hello ';
$body = 'world';
$smarty->assign('content_name',$content_name);
$smarty->assign($content_name.'_title',$title);
$smarty->assign($content_name.'_body',$body);
Smarty
{$content_name} //body
{${$content_name}_title} //hello
{${$content_name}_body} //world
{${$content_name}_title}{${$content_name}_body} my {$content_name} is awesome
//hello world my body is awesome
This is the dynamic way to use it. Even if its not the best way in this case :)
If you have kind of objects or multidimensional array... and you like to iterate them, you have to care about the whole string and not just the number...
For example:
PHP
$arr = [
"attr1" => "hello ",
"attr2" => "world ",
"attr3" => "my body is awesome"
];
$smarty->assign('foobar', $arr);
Smarty
{for $i=1 to 3}
{$foobar.{"attr$i"}} //works (whole name must be string var mix)
//{$foobar.attr{"$i"}} //fails
//{$foobar.attr{$i}} //fails
{/for}
But using {$foobar{$i}} on a simple array would work.
For all who need it, enjoy.
As per my comment on using an array instead of dynamic variables, here's an example of how to add the vars to an array:
php:
$vars = array();
function whatever() {
global $vars;
$vars[] = array(
'firstname' => 'Mike',
'surname' => 'Smith'
);
}
$smarty->assign('vars', $vars);
smarty:
{section name=loop loop=$vars}
Name: {$vars[loop].firstname} {$vars[loop].surname}
{/section}