Converting output of `hg history` into a dot file - mercurial

How can I take the output of hg history and convert it into a dot file?

You are looking for this extension.

I wrote a script to do this (and called it hghistory2dot.pl). See its usage below the code:
#!/usr/bin/perl
print "digraph {\n";
$first = 1;
$cset = ();
sub printedge {
my $one = csetstr(shift(#_));
my $two = csetstr(shift(#_));
print $one, " -> ", $two, ";\n";
}
sub csetstr {
my $csetid = shift(#_);
$csetid =~ s/\s//;
$csetid =~ s/\\n//;
return "cset_" . $csetid;
}
while($line = <> ) {
if (!($line eq "\n") ) {
$line =~ s/\n/\\n/;
push(#cset, $line);
}
else {
print csetstr($current), " [shape=record label=\"", #cset, "\"];\n";
#cset = ();
}
if( $line =~ m/^changeset/ ) {
#arr = split(/:/, $line);
$arr[2] =~ s/\s//;
if( ! $parent_found && ! $first) {
#previous changeset had no defined parent; therefore this one is the implied parent.
printedge($current, $arr[2]);
}
$current = $arr[2];
$parent_found = 0;
$first = 0;
}
elsif($line =~ m/^parent/) {
$parent_found = 1;
#arr = split(/:/, $line);
$arr[2] =~ s/\s//;
printedge($current, $arr[2]);
}
}
print "}\n";
hg history | hghistory2dot.pl | dot -Tpng > tree.png

Related

How to convert txt into html format using shell/bash

I have below data in a text file:
Details_A
name: A1
Valid: A1_Value
name: A2
Valid: A2_Value
Details_A2
name: A2
Valid: A2_Value
name: A2
Valid: A2_Value
which I am trying to convert into in below html table:
Details
You can use awk like this :
awk 'BEGIN {
x = 0;
print "<table border="1">"
}
{
if (NF == 1){
print "<tr ><td colspan="2">"$i"</td>";
print "</tr>"
} else {
if (x == 0){
x++;
print "<tr><td>"$i"</td>"
} else {
x = 0;
print "<td>"$i"</td></tr>"
}
}
}
END {
print "</table>"
}' input.txt > table.html
Feel free to add any additional style
For older version of awk, you can use the following, tested on an awk implementation of 2009-11-26 (from one-true-awk) :
awk 'BEGIN {
x = 0;
y = 0;
print "<table border="1">"
}
{
for (i = 1; i<=NF ; i++){
if (NF == 1){
print "<tr ><td colspan="2">"$i"</td></tr>";
} else {
if (x == 0 && y == 0){
print "<tr><td>"$i" ";
x++;
}
else if (x == 0 && y == 1){
print "<td>"$i" ";
x++;
}
else if (x==(NF-1)){
x = 0;
y++;
if (y == 2){
y = 0;
print ""$i"</td></tr>";
}
else{
print ""$i"</td>";
}
}
else {
print ""$i" ";
x++;
}
}
}
}
END {
print "</table>"
}' input.txt > table.html
For this last version, x is incremented at each space delimiter until we reach NF-1 which is the last word and we should put an ending </td>. The decision for the ending </tr> depends on the value of y which is incremented at each line and re-initialized when the max count of <td> is reached (here 2 <td> per <tr>)

PowerShell - Cannot reference attributes of elements in array returned by .getElementsByTagName()

I am retrieving an array of elements from a webpage via .getElementsByTagName(). I am then looping through the array and printing out the elements' titles:
$links = $ie.document.GetElementsByTagName("a")
Foreach($link in $links)
{
$link.title
}
This works. However a for loop better suits my needs, and this only seems to print out blank lines:
$links = $ie.document.GetElementsByTagName("a")
for($i=0; $i -lt $links.length; $i++)
{
$links[$i].title
}
Why does the second loop not print the title?
The 6 methods below all print all link titles, except Select-Object also prints an empty line when the title attribute is missing:
$requestUri = "http://google.com"
$ie = New-Object -ComObject "InternetExplorer.Application"
$ie.Navigate($requestUri)
while($ie.Busy) { Start-Sleep -Milliseconds 250 }
$links = $ie.Document.getElementsByTagName("a")
Write-Warning "ForEach-Object:"
$links | ForEach-Object { $_.title }
Write-Warning "Select-Object:"
$links | Select-Object title
Write-Warning "foreach:"
foreach($link in $links) { $link.title }
Write-Warning "for (from 0):"
for($i = 0; $i -lt $links.Length; $i++) {
$links[$i].title
}
Write-Warning "for (from 1):"
for($i = 1; $i -le $links.Length; $i++) {
$links[$i].title
}
Write-Warning "while:"
$i = 0
while($links[$i]) {
$links[$i].title
$i++
}
$ie.Quit()
Can you please try to run this on your system?
I would guess that $links = $ie.document.GetElementByTagName("a") and
and $links = $varDiv.GetElementsByTagName("a") are not Equivalent in that they are not providing you with the same object type.

display check or x boolean in table

I have atable in mysql database i'm fetching it to a html
print "<table>\n";
$result = $con->query($query); //return only the first row (we only need field names)
$row = $result->fetch(PDO::FETCH_ASSOC);
print "<tr>\n";
foreach ($row as $field => $value){
print "<th>$field</th>\n";
} // end foreach
print "</tr>\n"; //second query gets the data
$data = $con->query($query);
$data->setFetchMode(PDO::FETCH_ASSOC);
foreach($data as $row){
print " <tr>\n";
foreach ($row as $name=>$value){
print "<td>$value</td>\n";
} // end field loop
print "</tr>\n"; } // end record loop
print "</table>\n";
}
catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
} // end try
i have 2 columns that have a boolean value, i want that if column 6 = '0' then display x color:red; else display ✔ color:green;
Final Code
foreach ($row as $name=>$value){
if (($name == "paid" || $name == "added") && $value == "0"){
print "<td><span style='color: red;'>X</span></td>\n";
}
elseif (($name == "paid" || $name == "added") && $value == "1"){
print "<td><span style='color: lime;'>✔</span></td>\n";
}
else {
print "<td>$value</td>\n";
}
} // end field loop
Try:
foreach ($row as $name=>$value){
if ($name == "Column 6"){
if ($value == "0") {
print "<td><span style='color: red;">X</span></td>\n";
}
else {
print "<td>✔</td>\n";
}
}
else {
print "<td>$value</td>\n";
}
} // end field loop
There's no good way to colorize checkboxes, unless you want to use some complex css. However you could try and utilize before and after CSS for checkboxes as shown here: CSS ''background-color" attribute not working on checkbox inside <div>

Sage Pay v3.00 Integration

Can anyone help me incorporate the Sagepay v3.00 AES/CBC/PKCS#5 algorithm (encryption) into the following file. I'm really struggling to understand how to include so that customer data is encrypted to the new standard and then decrypted on the way back. Using Sagepay Form with a very old version of cs-cart, though have successfully managed to upgrade from version 2.22 to 2.23, but Sagepay are pulling all support from July.
Not sure how much of this script is relevant to the encryption:
<?php
if ( !defined('IN_CSCART') ) { die('Access denied'); }
if (defined('PAYMENT_NOTIFICATION')) {
// Get the password
$payment_id=db_get_field("SELECT $db_tables[payments].payment_id FROM $db_tables[payments] LEFT JOIN $db_tables[payment_processors] ON $db_tables[payment_processors].processor_id = $db_tables[payments].processor_id WHERE $db_tables[payment_processors].processor_script='protx_form.php'");
$processor_data = fn_get_payment_method_data($payment_id);
$result = "&".simpleXor(base64Decode($_REQUEST['crypt']), $processor_data["params"]["password"])."&";
preg_match("/Status=(.+)&/U", $result, $a);
if(trim($a[1]) == "OK") {
$pp_response['order_status'] = ($processor_data["params"]["transaction_type"] == 'PAYMENT') ? 'P' : 'O';
preg_match("/TxAuthNo=(.+)&/U", $result, $authno);
$pp_response["reason_text"] = "AuthNo: ".$authno[1];
preg_match("/VPSTxID={(.+)}/U", $result, $transaction_id);
$pp_response["transaction_id"] = #$transaction_id[1];
} else {
$pp_response['order_status'] = 'F';
preg_match("/StatusDetail=(.+)&/U", $result, $stat);
$pp_response["reason_text"] = "Status: ".trim($stat[1])." (".trim($a[1]).") ";
}
preg_match("/AVSCV2=(.*)&/U", $result, $avs);
if(!empty($avs[1])) {
$pp_response['descr_avs'] = $avs[1];
}
include $payment_files_dir.'payment_cc_complete.php';
fn_order_placement_routines($order_id);
}
else
{
global $http_location, $b_order, $_total_back;
$post_address = ($processor_data['params']['testmode'] != "N") ? "https://test.sagepay.com/gateway/service/vspform-register.vsp" : "https://live.sagepay.com/gateway/service/vspform-register.vsp";
$post["VPSProtocol"] = "2.23";
$post["TxType"] = $processor_data["params"]["transaction_type"];
$post["Vendor"] = htmlspecialchars($processor_data["params"]["vendor"]);
// Form Cart products
$strings = 0;
if (is_array($cart['products'])) {
$strings += count($cart['products']);
}
if (!empty($cart['products'])) {
foreach ($cart['products'] as $v) {
$_product = db_get_field("SELECT product FROM $db_tables[product_descriptions] WHERE product_id='$v[product_id]' AND lang_code='$cart_language'");
$products_string .= ":".str_replace(":", " ", $_product).":".$v['amount'].":".fn_format_price($v['subtotal']/$v['amount']).":::".fn_format_price($v['subtotal']);
}
}
if (!empty($cart['payment_surcharge'])) {
$products_string .= ":Payment surcharge:---:---:---:---:".fn_format_price($cart['payment_surcharge']);
$strings ++;
}
if (!empty($cart['shipping_cost'])) {
$products_string .= ":Shipping cost:---:---:---:---:".fn_format_price($cart['shipping_cost']);
$strings ++;
}
$post_encrypted .= "Basket=".$strings.$products_string;
$post["Crypt"] = base64_encode(simpleXor($post_encrypted, $processor_data["params"]["password"]));
$post["Crypt"] = htmlspecialchars($post["Crypt"]);
$msg = fn_get_lang_var('text_cc_processor_connection');
$msg = str_replace('[processor]', 'Protx Server', $msg);
echo <<<EOT
<html>
<body onLoad="document.process.submit();">
<form action="{$post_address}" method="POST" name="process">
<INPUT type=hidden name="VPSProtocol" value="{$post['VPSProtocol']}">
<INPUT type=hidden name="Vendor" value="{$post['Vendor']}">
<INPUT type=hidden name="TxType" value="{$post['TxType']}">
<INPUT type=hidden name="Crypt" value="{$post['Crypt']}">
<p>
<div align=center>{$msg}</div>
</p>
</body>
</html>
EOT;
}
exit;
//
// ---------------- Additional functions ------------
//
function simpleXor($InString, $Key) {
$KeyList = array();
$output = "";
for($i = 0; $i < strlen($Key); $i++){
$KeyList[$i] = ord(substr($Key, $i, 1));
}
for($i = 0; $i < strlen($InString); $i++) {
$output.= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)]));
}
return $output;
}
function base64Decode($scrambled) {
// Initialise output variable
$output = "";
// Fix plus to space conversion issue
$scrambled = str_replace(" ","+",$scrambled);
// Do encoding
$output = base64_decode($scrambled);
// Return the result
return $output;
}
?>
You could try dropping the following functions into the script, then swapping out simpleXor for encryptAes. Make sure that you also add an '#' symbol as the first character of the crypt string (and strip it off when decoding the response from Sage Pay).
function addPKCS5Padding($input)
{
$blockSize = 16;
$padd = "";
$length = $blockSize - (strlen($input) % $blockSize);
for ($i = 1; $i <= $length; $i++)
{
$padd .= chr($length);
}
return $input . $padd;
}
function removePKCS5Padding($input)
{
$blockSize = 16;
$padChar = ord($input[strlen($input) - 1]);
$unpadded = substr($input, 0, (-1) * $padChar);
return $unpadded;
}
function encryptAes($string, $key)
{
$string = addPKCS5Padding($string);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
return strtoupper(bin2hex($crypt));
}
function decryptAes($strIn, $password)
{
$strInitVector = $password;
$strIn = pack('H*', $hex);
$string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC,$strInitVector);
return removePKCS5Padding($string);
}
You could try this. I can't test it, so let me know how you get on.
<?php
if ( !defined('IN_CSCART') ) { die('Access denied'); }
if (defined('PAYMENT_NOTIFICATION')) {
// Get the password
$payment_id=db_get_field("SELECT $db_tables[payments].payment_id FROM $db_tables[payments] LEFT JOIN $db_tables[payment_processors] ON $db_tables
[payment_processors].processor_id = $db_tables[payments].processor_id WHERE $db_tables[payment_processors].processor_script='protx_form.php'");
$processor_data = fn_get_payment_method_data($payment_id);
#Rik added:
$result = "&".decryptAes($_REQUEST['crypt'], $processor_data["params"]["password"])."&";
#$result = "&".simpleXor(base64Decode($_REQUEST['crypt']), $processor_data["params"]["password"])."&";
preg_match("/Status=(.+)&/U", $result, $a);
if(trim($a[1]) == "OK") {
$pp_response['order_status'] = ($processor_data["params"]["transaction_type"] == 'PAYMENT') ? 'P' : 'O';
preg_match("/TxAuthNo=(.+)&/U", $result, $authno);
$pp_response["reason_text"] = "AuthNo: ".$authno[1];
preg_match("/VPSTxID={(.+)}/U", $result, $transaction_id);
$pp_response["transaction_id"] = #$transaction_id[1];
} else {
$pp_response['order_status'] = 'F';
preg_match("/StatusDetail=(.+)&/U", $result, $stat);
$pp_response["reason_text"] = "Status: ".trim($stat[1])." (".trim($a[1]).") ";
}
preg_match("/AVSCV2=(.*)&/U", $result, $avs);
if(!empty($avs[1])) {
$pp_response['descr_avs'] = $avs[1];
}
include $payment_files_dir.'payment_cc_complete.php';
fn_order_placement_routines($order_id);
}
else
{
global $http_location, $b_order, $_total_back;
$post_address = ($processor_data['params']['testmode'] != "N") ? "https://test.sagepay.com/gateway/service/vspform-register.vsp" :
"https://live.sagepay.com/gateway/service/vspform-register.vsp";
$post["VPSProtocol"] = "2.23";
$post["TxType"] = $processor_data["params"]["transaction_type"];
$post["Vendor"] = htmlspecialchars($processor_data["params"]["vendor"]);
// Form Cart products
$strings = 0;
if (is_array($cart['products'])) {
$strings += count($cart['products']);
}
if (!empty($cart['products'])) {
foreach ($cart['products'] as $v) {
$_product = db_get_field("SELECT product FROM $db_tables[product_descriptions] WHERE product_id='$v[product_id]' AND lang_code='$cart_language'");
$products_string .= ":".str_replace(":", " ", $_product).":".$v['amount'].":".fn_format_price($v['subtotal']/$v['amount']).":::".fn_format_price($v
['subtotal']);
}
}
if (!empty($cart['payment_surcharge'])) {
$products_string .= ":Payment surcharge:---:---:---:---:".fn_format_price($cart['payment_surcharge']);
$strings ++;
}
if (!empty($cart['shipping_cost'])) {
$products_string .= ":Shipping cost:---:---:---:---:".fn_format_price($cart['shipping_cost']);
$strings ++;
}
$post_encrypted .= "Basket=".$strings.$products_string;
#Rik added:
$post["Crypt"] = "#".encryptAes($post_encrypted, $processor_data["params"]["password"]);
# $post["Crypt"] = base64_encode(simpleXor($post_encrypted, $processor_data["params"]["password"]));
# $post["Crypt"] = htmlspecialchars($post["Crypt"]);
$msg = fn_get_lang_var('text_cc_processor_connection');
$msg = str_replace('[processor]', 'Protx Server', $msg);
echo <<<EOT
<html>
<body onLoad="document.process.submit();">
<form action="{$post_address}" method="POST" name="process">
<INPUT type=hidden name="VPSProtocol" value="{$post['VPSProtocol']}">
<INPUT type=hidden name="Vendor" value="{$post['Vendor']}">
<INPUT type=hidden name="TxType" value="{$post['TxType']}">
<INPUT type=hidden name="Crypt" value="{$post['Crypt']}">
<p>
<div align=center>{$msg}</div>
</p>
</body>
</html>
EOT;
}
exit;
//
// ---------------- Additional functions ------------
//
function simpleXor($InString, $Key) {
$KeyList = array();
$output = "";
for($i = 0; $i < strlen($Key); $i++){
$KeyList[$i] = ord(substr($Key, $i, 1));
}
for($i = 0; $i < strlen($InString); $i++) {
$output.= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)]));
}
return $output;
}
function base64Decode($scrambled) {
// Initialise output variable
$output = "";
// Fix plus to space conversion issue
$scrambled = str_replace(" ","+",$scrambled);
// Do encoding
$output = base64_decode($scrambled);
// Return the result
return $output;
}
#added by Rik
function addPKCS5Padding($input)
{
$blockSize = 16;
$padd = "";
$length = $blockSize - (strlen($input) % $blockSize);
for ($i = 1; $i <= $length; $i++)
{
$padd .= chr($length);
}
return $input . $padd;
}
function removePKCS5Padding($input)
{
$blockSize = 16;
$padChar = ord($input[strlen($input) - 1]);
$unpadded = substr($input, 0, (-1) * $padChar);
return $unpadded;
}
function encryptAes($string, $key)
{
$string = addPKCS5Padding($string);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
return strtoupper(bin2hex($crypt));
}
function decryptAes($strIn, $password)
{
#Sagepay specific - remove the '#'
$strIn = substr($strIn,1)
$strInitVector = $password;
$strIn = pack('H*', $hex);
$string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC,$strInitVector);
return removePKCS5Padding($string);
}
?>
/*First build your data. */
$data = 'variableA='.$this->variableA;
$data .= '&variableB='.$this->variableB;
...
$data .= '&variableZ='.$this->variableZ;
/** Encript data */
$dataEncrip = $this->encData($data);
/** function to Encrypt *//
public function encData($data){
$data = $this->pkcs5_pad( $data, 16);
$dataEnc = "#".bin2hex( mcrypt_encrypt( MCRYPT_RIJNDAEL_128,
$this->passwordToEncript,
$data,
MCRYPT_MODE_CBC,
$this->getPasswordToEncrypt()));
return $dataEnc;
}
/** Pkcs5_pad */
public function pkcs5_pad( $data, $blocksize ){
$pad = $blocksize - (strlen( $data ) % $blocksize);
return $data . str_repeat( chr( $pad ), $pad );
}

Truncate a HTML formatted text with SMARTY

I've got a variable which is formatted with random HTML code. I call it to {$text} and i truncate it.
The value is for example:
<div>Lorem <i>ipsum <b>dolor <span>sit </span>amet</b>, con</i> elit.</div>
If i truncate the text's first ~30 letters, I'll get this:
<div>Lorem <i>ipsum <b>dolor <span>sit
The problem is, I can't close the elements. So, I need a script, which check the <*> elements in the code (where * could be anything), and if it dont have a close tag, close 'em.
Please help me in this. Thanks.
Solution after hours, and 4 vote-up # stackoverflow:
PHP:
...
function closetags($content) {
preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $content, $result);
$openedtags = $result[1];
preg_match_all('#</([a-z]+)>#iU', $content, $result);
$closedtags = $result[1];
$len_opened = count($openedtags);
if (count($closedtags) == $len_opened) {
return $content;
}
$openedtags = array_reverse($openedtags);
for ($i=0; $i < $len_opened; $i++) {
if (!in_array($openedtags[$i], $closedtags)) {
$content .= '</'.$openedtags[$i].'>';
} else {
unset($closedtags[array_search($openedtags[$i], $closedtags)]);
}
}
return $content;
}
...
the TPL:
{$pages[j].text|truncate:300|#closetags}
Pull out all the open tags, push them into an array (array_1) one-by-one.
Pull out all of the closed tags, push them into an array (array_2) one-by-on (this includes self closing tags).
For the tags in the first array (array_1) that are not found in the second array (array_2), add them to the html.
[edit]
Of course, this method fails miserably if you do not write proper html... but whatchagonnado?
Another way would be to look ahead in the string to see which tags are closed and close them as needed.
To simplify, if the code is valid XML before truncating and you don't cut off tags in half, the algorithm would be something like this:
Push opening tags onto a stack
Pop them off when you find the closing tag (which will match if the code is valid)
When you get to the end, start popping to create closing. The remaining tags should be appended to the original (truncated) text.
Example:
<div>Lorem <i>ipsum <b>dolor <span>sit </span>amet</b><div>
Push "div","i","b","span"
Found closing tag "span"
Pop "span"
Found closing tag "b"
Pop "b"
Push "div"
End of truncated text
Pop "div" --> add </div> to text
Pop "b" --> add </b> to text
Pop "i" --> add </i> to text
Pop "div" --> add </div> to text
End
for other people like me and you I found this code ,I think is a better solution
add this file named "modifier.html_substr.php"
<?php
/*
* Smarty plugin
*
-------------------------------------------------------------
* File: modifier.html_substr.php
* Type: modifier
* Name: html_substr
* Version: 1.0
* Date: June 19th, 2003
* Purpose: Cut a string preserving any tag nesting and matching.
* Install: Drop into the plugin directory.
* Author: Original Javascript Code: Benjamin Lupu <hide#address.com>
* Translation to PHP & Smarty: Edward Dale <hide#address.com>
* Modification to add a string: Sebastian Kuhlmann <hide#address.com>
* Modification to put the added string before closing <p> or <li> tags by Peter Carter http://www.podhawk.com
-------------------------------------------------------------
*/
function smarty_modifier_html_substr($string, $length, $addstring="")
{
//some nice italics for the add-string
if (!empty($addstring)) $addstring = "<i> " . $addstring . "</i>";
if (strlen($string) > $length) {
if( !empty( $string ) && $length>0 ) {
$isText = true;
$ret = "";
$i = 0;
$currentChar = "";
$lastSpacePosition = -1;
$lastChar = "";
$tagsArray = array();
$currentTag = "";
$tagLevel = 0;
$addstringAdded = false;
$noTagLength = strlen( strip_tags( $string ) );
// Parser loop
for( $j=0; $j<strlen( $string ); $j++ ) {
$currentChar = substr( $string, $j, 1 );
$ret .= $currentChar;
// Lesser than event
if( $currentChar == "<") $isText = false;
// Character handler
if( $isText ) {
// Memorize last space position
if( $currentChar == " " ) { $lastSpacePosition = $j; }
else { $lastChar = $currentChar; }
$i++;
} else {
$currentTag .= $currentChar;
}
// Greater than event
if( $currentChar == ">" ) {
$isText = true;
// Opening tag handler
if( ( strpos( $currentTag, "<" ) !== FALSE ) &&
( strpos( $currentTag, "/>" ) === FALSE ) &&
( strpos( $currentTag, "</") === FALSE ) ) {
// Tag has attribute(s)
if( strpos( $currentTag, " " ) !== FALSE ) {
$currentTag = substr( $currentTag, 1, strpos( $currentTag, " " ) - 1 );
} else {
// Tag doesn't have attribute(s)
$currentTag = substr( $currentTag, 1, -1 );
}
array_push( $tagsArray, $currentTag );
} else if( strpos( $currentTag, "</" ) !== FALSE ) {
array_pop( $tagsArray );
}
$currentTag = "";
}
if( $i >= $length) {
break;
}
}
// Cut HTML string at last space position
if( $length < $noTagLength ) {
if( $lastSpacePosition != -1 ) {
$ret = substr( $string, 0, $lastSpacePosition );
} else {
$ret = substr( $string, $j );
}
}
// Close broken XHTML elements
while( sizeof( $tagsArray ) != 0 ) {
$aTag = array_pop( $tagsArray );
// if a <p> or <li> tag needs to be closed, put the add-string in first
if (($aTag == "p" || $aTag == "li") && strlen($string) > $length) {
$ret .= $addstring;
$addstringAdded = true;
}
$ret .= "</" . $aTag . ">\n";
}
} else {
$ret = "";
}
// if we have not added the add-string already
if ( strlen($string) > $length && $addstringAdded == false) {
return( $ret.$addstring );
}
else {
return ( $ret );
}
}
else {
return ( $string );
}
}
?>
usage
{$yourdata|html_substr:300:' ...'}