Calling a variable that is nowhere else - php

In the following code, from Beginning PHP and mySQL 5e, if acronym function is called without mentioning $matches, how ,in the definition of acronym, $matches is never linked to anything, but rather used in the isset($acronym[$matches[1]])) ?, How isset knows what is $matches in the first place?
The following is the code and I have tested that it is working.
I just cannot follow up with the use of an arbitrary term; $matches, and its use.
// This function will add the acronym's long form
// directly after any acronyms found in $matches
function acronym($matches) {
$acronyms = array(
'WWW' => 'World Wide Web',
'IRS' => 'Internal Revenue Service',
'PDF' => 'Portable Document Format');
if (isset($acronyms[$matches[1]]))
return $acronyms[$matches[1]] . " (" . $matches[1] . ")";
else
return $matches[1];
}
// The target text
$text = "The <acronym>IRS</acronym> offers tax forms in
<acronym>PDF</acronym> format on the <acronym>WWW</acronym>.";
// Add the acronyms' long forms to the target text
$newtext = preg_replace_callback("/<acronym>(.*)<\/acronym>/U", 'acronym',
$text);
print_r($newtext);
The output is:
The Internal Revenue Service (IRS) offers tax forms inPortable Document Format (PDF) format on the World Wide Web (WWW).
Reminder: The input, for the function preg_replace_callback is:
The <acronym>IRS</acronym> offers tax forms in <acronym>PDF</acronym> format on the <acronym>WWW</acronym>.

The preg_replace_callback() function is written in that way, that it calls the function with a well defined argument. See the manual of this function:
A callback that will be called and passed an array of matched elements in the subject string. The callback should return the replacement string. This is the callback signature:
handler ( array $matches ) : string
So your function acronym() will get an array with the matches from the regex. Keep in mind that you are not calling the acronym() function by yourself, the function preg_replace_callback() does that for you (with the argument defined in the documentation).

Related

PHP function Delete characters in string Between Tokens Unless Tokens Match a specific String

Ok so here is what I am trying to do, I need a php function that I can pass 4 parameters.
1) A String (Containing Tokens with text between them)
2) A Start Token String Parameter
3) A Stop Token String Parameter
4) A DO NOT DELETE String Parameter
I want to pass a (1)long string to the function and have it remove all the multiple instances of the (2)Start Tokens and all the Text Until The (3)Stop Token, UNLESS the (4)Do NOT DELETE Parameter is present in that part of the String.
The Setup would be like this:
HERE is the way the function would be setup:
function CleanUpMyString($string-1, $start-2, $end-3, $keep-4){
// Working Code That Does The Work Here
}
The String That I could Pass To The Function May Look Like this examples:
$stringTEST = "This is the intro of the string, <<<This Part Would Be Deleted>>> in the next snippet of the string, <<<we will delete another part>>> This is going pretty well. <<<keep>We do not delete this part because of the added token part 'keep>'.>>> We will add some more rambling text here. Then we will add another snippet. <<<We will also delete this one.>>><<<keep>But in the end it is all good!>>>";
Assuming I called the function like this:
echo CleanUpMyString($stringTEST, '<<<', '>>>', 'keep>');
I would get the following output:
This is the intro of the string, in the next snippet of the string, This is going pretty well. We do not delete this part because of the added token part 'keep>'. We will add some more rambling text here. Then we will add another snippet. But in the end it is all good!
I have no control over the input string, so the tokens could occur anywhere in any number, and there is not rational order in which they may appear.
I really am not sure where to start. I took a look at this thread:
PHP function to delete all between certain character(s) in string
which I thought has been the closest thing to what I wanted, but I could not see how to extend the idea to my application. Any help would be seriously appreciated!
my suggestion is to use preg_replace_callback
<?php
function CleanUpMyString($string, $start, $end, $keep)
{
return preg_replace_callback(
'~' . preg_quote($start, '~') . '.+?' . preg_quote($end, '~') . '~',
function ($M) use ($start, $end, $keep) {
if (strpos($M[0], $keep)) {
return str_replace([$start, $end, $keep], '', $M[0]);
} else {
return '';
}
},
$string
);
}
$stringTEST = "This is the intro of the string, <<<This Part Would Be Deleted>>> in the next snippet of the string, <<<we will delete another part>>> This is going pretty well. <<<keep>We do not delete this part because of the added token part 'keep>'.>>> We will add some more rambling text here. Then we will add another snippet. <<<We will also delete this one.>>><<<keep>But in the end it is all good!>>>";
echo CleanUpMyString($stringTEST, '<<<', '>>>', 'keep>');
Hope this will help you out, Here i am using preg_match to gather all matching tokens from start to end and then we are iterating over matches to keep required portion of string and removing un-necessary part.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$stringTEST = "This is the intro of the string, <<<This Part Would Be Deleted>>> in the next snippet of the string, <<<we will delete another part>>> This is going pretty well. <<<keep>We do not delete this part because of the added token part 'keep>'.>>> We will add some more rambling text here. Then we will add another snippet. <<<We will also delete this one.>>><<<keep>But in the end it is all good!>>>";
echo CleanUpMyString($stringTEST, "<<<", ">>>", "keep>");
function CleanUpMyString($stringTEST, $start, $end, $keep)
{
$startQuotes= preg_quote($start);
$endQuotes= preg_quote($end);
preg_match_all("/$startQuotes.*?(?:$endQuotes)/", $stringTEST,$matches);
foreach($matches[0] as $key => $value)
{
if(stristr($value, $start.$keep)!==false)
{
$stringTEST= substr_replace($stringTEST,"",strpos($stringTEST, $start.$keep), strlen($start.$keep));;
$stringTEST= substr_replace($stringTEST,"",strpos($stringTEST, $end), strlen($end));
}
else
{
$stringTEST= str_replace($value, "", $stringTEST);
}
}
return $stringTEST;
}

Replace placeholder in XML file with PHP function

I have an XML file that contains FAQs, but some of the contents of the answers need to use PHP functions to output appropriate content.
How can I find the placeholders within the answers, and replace them with PHP functions? Ideally, I would like to be able to have the functions set as variables to be changeable across multiple websites this code would be used on.
XML File (placeholders in last block, %LOCAL_NO% and %PREM_NO%)
<?xml version="1.0" encoding="UTF-8"?>
<faqs>
<faq>
<category>General</category>
<q>How old do I have to be to use your service?</q>
<a>You must be at least 18 years of age.</a>
</faq>
<faq>
<category>General</category>
<q>How long is a psychic reading?</q>
<a>The length of a psychic reading is completely up to you. It depends on the number and complexity of the questions you ask. The average length of a reading is 15 to 20 minutes.</a>
</faq>
<faq>
<category>General</category>
<q>Can I choose the psychic I speak with?</q>
<a>Of course! You can choose who you would like to speak to by selecting your desired psychic's profile and following the online prompts via the online booking page, or call us on %PREM_NO% and enter their PIN, or call %LOCAL_NO% and our live receptionists will connect you to a psychic that matches your requirements!</a>
</faq>
</faqs>
PHP output
<?php // General FAQs
$faqGeneral = $xml->xpath("/faqs/faq[category='General']");
echo "<h2>General</h2>";
foreach ($faqGeneral as $faq) { ?>
<h3><?php echo $faq->q; ?></h3>
<p><?php echo $faq->a; ?></p>
<?php } ?>
That looks like a case for preg_replace_callback, of course called before evaluating the XML. Which also ensures that the "PHP-echoed" values do not break XML syntax.
$data = array(
'tags' => array(
'PREM_NO' => '1-800-CSICOP',
)
);
$filledXML = preg_replace_callback(
'#%(\\w+)%#', // A-Z and underscore between %%'s
function ($matches) use ($data) {
switch($matches[1]) {
case 'PREM_NO':
case 'WHATEVER':
return $data['tags'][$matches[1]];
case 'YYYYMMDD':
return date('Y-m-d');
default:
return '';
}
},
$xmlString);
// $xml = loadXML($xmlString);
$xml = loadXML($filledXML);
This allows for special tags such as YYYYMMDD to return runtime-calculated values, as well as externals. You can even include a PDO handle in $data and be able to run SQL queries inside the function.
A simpler version
$tags = array(
'%PREM_NO%' => '12345',
'%YYYYMMDD%' => date('Y-m-d'),
// ... et cetera
);
$filledXML = str_replace(array_keys($tags), array_values($tags), $xmlString);
If you know the strings to match and the values before (i.e., not dynamic) then you can just do a str_replace inline.
If they are dynamic then you can grab the values from your database (or wherever you are storing them) and then loop through and str_replace them.
Or, you could use regex, something like /(\%[a-z_]+\%)/i. For that you can look into preg_match_all.
str_replace in the PHP manual
preg_match_all in the PHP manual
Update: You can use arrays as parametera for str_replace. E.g.,
$find = array('%PREM_NO%', '%LOCAL_NO%');
$replace = array('012345', '67890');
$answer = str_replace($find, $replace, $faq->a);

Create URL with only A-Z characters that includes variable and extension

I am trying to create file links based a variable which has a "prefix" and an extension at the end.
Here's what I have:
$url = "http://www.example.com/mods/" . ereg("^[A-Za-z_\-]+$", $title) . ".php";
Example output of what I wish to have outputted (assuming $title = testing;):
http://www.example.com/mods/testing.php
What it currently outputs:
http://www.example.com/mods/.php
Thanks in advance!
Perhaps this is what you need:
$title = "testing";
if(preg_match("/^[A-Za-z_\-]+$/", $title, $match)){
$url = "http://www.example.com/mods/".$match[0].".php";
}
else{
// Think of something to do here...
}
Now $url is http://www.example.com/mods/testing.php.
Do you want to keep letters and remove all other chars in the URL?
In this case the following should work:
$title = ...
$fixedtitle=preg_replace("/[^A-Za-z_-]/", "", $title);
$url = "http://www.example.com/mods/".$fixedtitle.".php";
the inverted character class will remove everything you do not want.
OK first it's important for you to realize that ereg() is deprecated and will eventually not be available as a command for php, so to prevent an error down the road you should use preg_match instead.
Secondly, both ereg() and preg_match output the status of the match, not the match itself. So
ereg("^[A-Za-z_\-]+$", $title)
will output an integer equal to the length of the string in $title, 0 if there's no match and 1 if there's a match but you didn't pass it another variable to store the matches in.
I'm not sure why it's displaying
http://www.example.com/mods/.php
It should actually be outputting
http://www.example.com/mods/1.php
if everything was working correctly. So there is something going on there, and it's definitely not doing what you want it to. You need to pass another variable to the function that will store all the matches found. If the match is successful (which you can check using the return value of the function) then that variable will be an array of all matches.
Note that with preg_match by default only the first match will be returned. but it will still generate an array (which can be used to get isolated portions of the match) whereas preg_match_all will match multiple things.
See http://www.php.net/manual/en/function.preg-match.php for more details.
Your regex looks more or less correct
So the proper code should look something like:
$title = 'testing'; //making sure that $title is what we think it is
if (preg_match('/^[A-Za-z_\-]+$/',$title,$matches)) {
$url = "http://www.example.com/mods/" . $matches[0] . ".php";
} else {
//match failed, put error code in here
}

Can I add variable name within a string?

I am creating an OpenCart extension where the admin can change his email templates using the user interface in the admin panel.
I would like the user to have the option to add variables to his custom email templates. For example he could put in:
Hello $order['customer_firstname'], your order has been processed.
At this point $order would be undefined, the user is simply telling defining the message that is to be sent. This would be stored to the database and called when the email is to be sent.
The problem is, how do I get "$order['customer_firstname']" to become a litteral string, and then be converted to a variable when necessary?
Thanks
Peter
If I understand your question correctly, you could do something like this:
The customer has a textarea or similar to input the template
Dear %NAME%, blah blah %SOMETHING%
Then you could have
$values = array('%SOMETHING%' => $order['something'], '%NAME%' => $order['name']);
$str = str_replace(array_keys($values), array_values($values), $str);
the user will be using around 40 variables. Is there a way I can set it to do that for each "%VARIABLE%"?
Yes, you can do so for each variable easily with the help of a callback function.
This allows you, to process each match with a function of your choice, returning the desired replacement.
$processed = preg_replace_callback("/%(\S+)%/", function($matches) {
$name = $matches[1]; // between the % signs
$replacement = get_replacement_if_valid($name);
return $replacement;
},
$text_to_replace_in
);
From here, you can do anything you like, dot notation, for example:
function get_replacement_if_valid($name) {
list($var, $key) = explode(".", $name);
if ($var === "order") {
$order = init_oder(); // symbolic
if(array_key_exists($key, $order)) {
return $order[$key];
}
}
return "<invalid key: $name>";
}
This simplistic implementation allows you, to process replacements such as %order.name% substituting them with $order['name'].
You could define your own simple template engine:
function template($text, $context) {
$tags = preg_match_all('~%([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)%~', $text, $matches);
for($i = 0; $i < count($matches[0]); $i++) {
$subject = $matches[0][$i];
$ctx = $matches[1][$i];
$key = $matches[3][$i];
$value = $context[$ctx][$key];
$text = str_replace($subject, $value, $text);
}
return $text;
}
This allows you to transform a string like this:
$text = 'Hello %order.name%. You have %order.percent%% discount. Pay a total ammount of %payment.ammount% using %payment.type%.';
$templated = template($text, array(
'order' => array(
'name' => 'Alex',
'percent' => 20
),
'payment' => array(
'type' => 'VISA',
'ammount' => '$299.9'
)
));
echo $templated;
Into this:
Hello Alex. You have 20% discount. Pay a total ammount of $299.9 using VISA.
This allows you to have any number of variables defined.
If you want to keep the PHP-syntax, then a regex would be appropriate to filter them:
$text = preg_replace(
"/ [$] (\w+) \[ '? (\w+) \'? \] /exi",
"$$1['$2']", # basically a constrained eval
$text
);
Note that it needs to be executed in the same scope as $order is defined. Else (and preferrably) use preg_replace_callback instead for maximum flexibility.
You could also allow another syntax this way. For example {order[customer]} or %order.customer% is more common and possibly easier to use than the PHP syntax.
You can store it as Hello $order['customer_firstname'] and while accessing make sure you have double-quotes "" to convert the variable to its corresponding value.
echo "Hello $order['customer_firstname']";
Edit: As per the comments, a variation to Prash's answer,
str_replace('%CUSTOMERNAME%', $order['customer_name'], $str);
What you're looking for is:
eval("echo \"" . $input . "\";");
but please, PLEASE don't do that, because that lets the user run any code he wants.
A much better way would be a custom template-ish system, where you provide a list of available values for the user to drop in the code using something like %user_firstname%. Then, you can use str_replace and friends to swap those tags out with the actual values, but you can still scan for any sort of malicious code.
This is why Markdown and similar are popular; they give the user control over presentation of his content while still making it easy to scan for HTML/JS/PHP/SQL injection/anything else they might try to sneak in, because whitelisting is easier than blacklisting.
Perhaps you can have a template like this:
$tpl = "Hello {$order['customer_firstname']}, your order has been processed.".
If $order and that specific key is not null, you can use echo $tpl directly and show the content of 'customer_firstname' key in the text. The key are the curly braces here.

Using preg_replace_callback to identify and manipulate latex code

I have latex + html code somewhere in the following form:
...some text1.... \[latex-code1\]....some text2....\[latex-code2\]....etc
Firstly I want to obtain the latex codes in an array codes[] to be able to send them to a server for rendering, so that
code[0]=latex-code1, code[1]=latex-code2, etc
Secondly, I want to modify this text so that it looks like:
...some text1.... <img src="root/1.png">....some text2....<img src="root/2.png">....etc
i.e, the i-th latex code fragment is replaced by the link to the i-th rendered image.
I have been trying to do this with preg_replace_callback and preg_match_all but being new to PHP haven't been able to make it work. Please advise.
If you're looking for codez:
$html = '...some text1.... \[latex-code1\]....some text2....\[latex-code2\]....etc';
$codes = array();
$count = 0;
$replace = function($matches) use (&$codes, &$count) {
list(, $codes[]) = $matches;
return sprintf('<img src="root/%d.png">', ++$count);
};
$changed = preg_replace_callback('~\\\\\\[(.+?)\\\\\\]~', $replace, $html);
echo "Original: $html\n";
echo "Changed : $changed\n\nLatex Codes: ", print_r($codes, 1), "Count: ", $count;
I don't know at which part you've got the problems, if it's the regex pattern, you use characters inside your markers that needs heavy escaping: For PHP and PCRE, that's why there are so many slashes.
Another tricky part is the callback function because it needs to collect the codes as well as having a counter. It's done in the example with an anonymous function that has variable aliases / references in it's use clause. This makes the variables $codes and $count available inside the callback.

Categories