How to limit a text by characters - php

I have a PHP project ( Using laravel ) and I need to show just part of an article in the view . For example this is the full content of article :
Hello World It is my First Post and I decided to share it on my
personal blog .
and I wanted to show part of that in the recent posts part such this :
Hello world it is ...
I made a function but it doesn't work when I want to limit the text ( But there is no problem with short texts ) This is my function :
function limitText($text,$length=300) {
if(strlen($text)<$length) {
$new = $text."...";
return $new;
}
$new = substr($text,0,$length);
$new = $new."...";
return $new; }
any idea or suggestion ?

One way to do that is to use str_limit()
$value = str_limit('Just string', 4, '...'); // Output is 'Just...'
The str_limit function limits the number of characters in a string. The function accepts a string as its first argument and the maximum number of resulting characters as its second argument

Related

How can I str_replace partially in PHP in a dynamic string with unknown key content

Working in WordPress (PHP). I want to set strings to the database like below. The string is translatable, so it could be in any language keeping the template codes. For the possible variations, I presented 4 strings here:
<?php
$string = '%%AUTHOR%% changed status to %%STATUS_new%%';
$string = '%%AUTHOR%% changed status to %%STATUS_oldie%%';
$string = '%%AUTHOR%% changed priority to %%PRIORITY_high%%';
$string = '%%AUTHOR%% changed priority to %%PRIORITY_low%%';
To make the string human-readable, for the %%AUTHOR%% part I can change the string like below:
<?php
$username = 'Illigil Liosous'; // could be any unicode string
$content = str_replace('%%AUTHOR%%', $username, $string);
But for status and priority, I have different substrings of different lengths.
Question is:
How can I make those dynamic substring be replaced on-the-fly so that they could be human-readable like:
Illigil Liosous changed status to Newendotobulous;
Illigil Liosous changed status to Oldisticabulous;
Illigil Liosous changed priority to Highlistacolisticosso;
Illigil Liosous changed priority to Lowisdulousiannosso;
Those unsoundable words are to let you understand the nature of a translatable string, that could be anything other than known words.
I think I can proceed with something like below:
<?php
if( strpos($_content, '%%STATUS_') !== false ) {
// proceed to push the translatable status string
}
if( strpos($_content, '%%PRIORITY_') !== false ) {
// proceed to push the translatable priority string
}
But how can I fill inside those conditionals efficiently?
Edit
I might not fully am clear with my question, hence updating the query. The issue is not related to array str_replace.
The issue is, the $string that I need to detect is not predefined. It would come like below:
if($status_changed) :
$string = "%%AUTHOR%% changed status to %%STATUS_{$status}%%";
else if($priority_changed) :
$string = "%%AUTHOR%% changed priority to %%PRIORITY_{$priority}%%";
endif;
Where they will be filled dynamically with values in the $status and $priority.
So when it comes to str_replace() I will actually use functions to get their appropriate labels:
<?php
function human_readable($codified_string, $user_id) {
if( strpos($_content, '%%STATUS_') !== false ) {
// need a way to get the $status extracted from the $codified_string
// $_got_status = ???? // I don't know how.
get_status_label($_got_status);
// the status label replacement would take place here, I don't know how.
}
if( strpos($_content, '%%PRIORITY_') !== false ) {
// need a way to get the $priority extracted from the $codified_string
// $_got_priority = ???? // I don't know how.
get_priority_label($_got_priority);
// the priority label replacement would take place here, I don't know how.
}
// Author name replacement takes place now
$username = get_the_username($user_id);
$human_readable_string = str_replace('%%AUTHOR%%', $username, $codified_string);
return $human_readable_string;
}
The function has some missing points where I currently am stuck. :(
Can you guide me a way out?
It sounds like you need to use RegEx for this solution.
You can use the following code snippet to get the effect you want to achieve:
preg_match('/%%PRIORITY_(.*?)%%/', $_content, $matches);
if (count($matches) > 0) {
$human_readable_string = str_replace("%%PRIORITY_{$matches[0]}%%", $replace, $codified_string);
}
Of course, the above code needs to be changed for STATUS and any other replacements that you require.
Explaining the RegEx code in short it:
/
The starting of any regular expression.
%%PRIORITY_
Is a literal match of those characters.
(
The opening of the match. This is going to be stored in the third parameter of the preg_match.
.
This matches any character that isn't a new line.
*?
This matches between 0 and infinite of the preceding character - in this case anything. The ? is a lazy match since the %% character will be matched by the ..
Check out the RegEx in action: https://regex101.com/r/qztLue/1

Get second item with preg_match in php

I am getting text between two tags with PHP (from a HTML).
a sample code i use is this :
function GDes($url) {
$fp = file_get_contents($url);
if (!$fp) return false;
$res = preg_match("/<description>(.*)<\/description>/siU", $fp, $title_matches);
if (!$res) return false;
$description = preg_replace('/\s+/', ' ', $title_matches[1]);
$description = trim($description);
return $description;
}
It gives between the description tags, But my problem is that if the page have to description tags, it will give the first one that i don't need it.
I need to get the second one.
For example, If my HTML is this :
<description>No need to this</description>
<description>I NEED THIS ONE</description>
I need to give the second description tag with that function above.
What changes the function needed ?
Use preg_match_all instead. It will create an array with all matches.
You can keep your code as is, just replace preg_match with preg_match_all.
Then you have to use $title_matches[1][1] instead of $title_matches[1] in your preg_replace call, since the $title_matches is now a multidimensional array.

PHP Function and variables stored in a string in a database

I need to store data within a database, when I get the data from the database I need functions and variables in the string to be worked out as such.
Example
$str = "<p>Dear {$this->name},</p>"
I then store this in the database, and when I retrieve the string and run it through
eval("\$detail= \"$detail\";");
then the variable gets populated with the name. This is exactly what I needed and works fine.
The problem is I want to run a function with this variable as the parameter.
example. I would like to ucwords the variable.
I have tried:
$str = "<p>Dear {ucwords($this->name)},</p>" //just echoed {ucword(->name)},
$str = "<p>Dear {ucwords($this->name)},</p>" //Fatal error: Function name must be a string,
Am I going in the right direction?
Is this at all possible?
You don't need to keep PHP code in database. This is a bad practice and also can lead to security vulnerabilities.
Instead store in database string like this:
<p>Dear [name],</p>
And when you retrieve it you can just do:
$stringFromDb = str_replace("[name]", $this->name, $stringFromDb);
or
$stringFromDb = str_replace("[name]", ucwords($this->name), $stringFromDb);
Other common approach is to use sprintf. So you need to store in database string with %s as placeholders for values.
Example:
<p>Dear %s,</p>
and replace with
$stringFromDb = sprintf($stringFromDb, ucwords($this->name));
What you seem to be looking for is a simple templating language.
It's been a long while since I've written PHP (and I suddenly remember why...), but here's something I whipped up.
It should support both objects ($a->name) and arrays ($a["name"]) as input objects.
You can add new filters (name -> function name mapping) in $valid_filters.
$valid_filters = array("title" => "ucfirst", "upper" => "strtoupper");
function _apply_template_helper($match) {
global $_apply_template_data, $valid_filters;
$var = $match[1];
$filter = $valid_filters[trim($match[2], ':')];
$value = is_array($_apply_template_data) ? $_apply_template_data[$var] : $_apply_template_data->$var;
if($filter && !empty($value)) $value = call_user_func($filter, $value);
return !empty($value) ? $value : $match[0];
}
function apply_template($template, $data) {
global $_apply_template_data;
$_apply_template_data = $data;
$result = preg_replace_callback('/\{\{(.+?)(:.+?)?\}\}/', "_apply_template_helper", $template);
$_apply_template_data = null;
return $result;
}
How to use it:
$template = "Hello {{name:title}}, you have been selected to win {{amount}}, {{salutation:upper}}";
echo apply_template($template, array("name"=>"john", "amount" => '$500,000', "salutation" => "congratulations"));
The result:
Hello John, you have been selected to win $500,000, CONGRATULATIONS
I have found the following works,
If i contain the function within the class itself then it can be called using the following code
<p>Dear {\$this->properCase(\$this->rl_account->name)},</p>
But i would like to be able to do this now without having the database have the code as Alex Amiryan mentions earlier.

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.

preg_replace_all() related issue

I am currently making a BBCode class for my website.
I need to do the following.
function bbCode([skill]Q[/skill]_________[skill]Q[/skill]_________[skill]Q[/skill]);
bbCode function has to replace all Q's between [skill] and [/skill] tags, and replace it with $skillArray['Q'] value. ($skillArray is character dependant.)
How can I do this?
A little clearer version is:
For example you're on a page of "Orc" character.
[skill]Q[/skill] tag should get "Orc's Q skill name" automatically.
For example you're on a page of "Hunter" character.
[skill]Q[/skill] tag should get "Hunter's Q skill name" automatically.
Ps. Don't want to use explode.
Assuming the tags you want to be replaced are within some form of template, you could use file_get_contents and then loop through the tags you want to replace with the desired values, for example:
$file = file_get_contents ( 'yourfile.php' );
$skillArray = array ( 'Q' => 'Hunter name' );
foreach ( $skillArray as $key => $val )
{
$file = str_replace ( '[skill]' . $key . '[\skill]', $val, $file );
}
Thats just a completely rough example, but if I'm understanding what you are trying to do; that should be along the right lines....
This is what you need
$data = "[skill]Q[/skill]_________[skill]Q[/skill]_________[skill]Q[/skill]";
$r['Q'] = "Yahoo";
function b($a){
global $r;
return $r[$a[1]];
}
$data = preg_replace_callback('|\[skill\](Q)\[\/skill\]|', 'b' , $data);
var_dump($data);
If you want to replace all the Qs with single "Yahoo" use Q+ instead of Q. If you want to match all words use \w+.
<?php
$skillArray=array('Q'=>'fishing');
$txt="test [skill]Q[/skill] test";
$txt=preg_replace("#\[skill\](.*)\[\/skill\]#e",'$skillArray["$1"]',$txt);
echo $txt; //test fishing test
?>

Categories