webForumDet fria alternativet

Replace - snyggare sätt att lösa detta på?

PHP

4 svar · 465 visningar · startad av bassebhu

Medlem sedan nov. 20016 480 inlägg
Frågan#1

Har gjort ett litet script som hämtar rader från databasen. Min funktion getarchive() innehåller dels vilket parent-namn den ska hämta poster som tillhör och dels hur jag vill att det ska formateras. Jag vill kunna hämta önskade fält från databasen och kunna lägga på funktioner på dem i efterhand. Just nu har jag bara en replace på tre fördefinerade fält och kan inte göra nåt alls med dem i efterhand.

Så här ser min kod ut för att skriva ut poster:

$structure = '<dt>{$title}</dt>
<dd>{$datetime}</dd>
<dd>{$content}</dd>';
getarchive('nyheter', $structure);

Funktionen för databashämtet:

function getarchive ($parent, $structure) {

	$sql = "SELECT * FROM archive WHERE parent = '".$parent."'";
	$result = mysql_query($sql);

	$data = NULL;

	while($row = mysql_fetch_array($result)) {

		$datastr = str_replace('{$title}', $row['title'], $structure);
		$datastr = str_replace('{$datetime}', $row['datetime'], $datastr);
		$datastr = str_replace('{$content}', $row['content'], $datastr);
		$data .= $datastr;
	}

	return $data;

}

Jag hittar alltså på {$variabel} för att kunna ersätta dem, men jag tycker att det måste kunna göras på något smartare sätt. Förslag? Blanda in RegExp och lite sånt?

Stort tack!

Medlem sedan aug. 20039 340 inlägg
#2

Typ så här:

$structure = '<dt>{$title}</dt>
<dd>{$datetime}</dd>
<dd>{$content}</dd>';
$structure_allowed_items=Array('title', 'datetime', 'content');
getarchive('nyheter', $structure, $structure_allowed_items);

function getarchive ($parent, $structure, $structure_allowed_items) {

	$sql = "SELECT * FROM archive WHERE parent = '".$parent."'";
	$result = mysql_query($sql);

	$replace_structure_element = create_function('$matches',
	'if (in_array($matches[1], $structure_allowed_items)){
		return $row[$matches[1]]
	}else{
		return $matches[0]
	} ');

	$data = NULL;

	while($row = mysql_fetch_array($result)) {
		$datastr = preg_replace_callback('/\{\$([a-z0-1_]+)\}/i', 
			$replace_structure_element,
			$structure);

		$data .= $datastr;
	}

	return $data;

}

Otestat, kan innehålla småfel.
preg_replace_callback söker med ett regex. För varje natchning anropas en funktion. I detta fall skapar jag funktionen med create_function. Funktionen som skapas kollar om strängen som anropas är tillåten, för säkerhets skull. Är den det hämtas motsvarande rad i databasen. $matches[1] bör referera till ([a-z0-1_]+) i uttrycket. Annars returneras matchningen oförändrad, vilket alltså gör att man varken får tillbaka lösenordet eller ett tomrum om man lägger in {$password} i strängen. ( ;) )

Medlem sedan nov. 20016 480 inlägg
#3

Tack!

Jag får:
Notice: Undefined variable: structure_allowed_items...
samt:
Warning: in_array() [function.in-array]: Wrong datatype for second argument...

Ska det in nån global till create_function?

Jag lade även till två semikolon efter return $row[$matches[1]] och return $matches[0]

Är det möjligt att få det så att man skulle kunna skriva t.ex.:

$structure = '<dt>{strtoupper($title)}</dt>
<dd>{$datetime}</dd>
<dd>{$content}</dd>';

och den känner av om man har lagt något runt variablerna? t.ex. strtoupper eller en egen funktion eller nåt annat. Så att man kan behandla dem som vanliga variabler i princip.

Tack!

Medlem sedan aug. 20039 340 inlägg
#4

bassebhu skrev:

Ska det in nån global till create_function?

Så kan man göra, men det är inte rätt! Undvik globals som pesten, åtminstone för saker som inte ska vara globala egentligen. Föreställ dig t ex att du anropar funktionen rekursivt i en framtida version...

bassebhu skrev:

Är det möjligt att få det så att man skulle kunna skriva t.ex.:

$structure = '<dt>{strtoupper($title)}</dt>
<dd>{$datetime}</dd>
<dd>{$content}</dd>';

och den känner av om man har lagt något runt variablerna? t.ex. strtoupper eller en egen funktion eller nåt annat. Så att man kan behandla dem som vanliga variabler i princip.

Så kan man göra, men det är inte rätt! En betydligt bättre metod är att sätta text-transform: uppercase; i CSS för elementen ifråga.

Fast jag lade till en sådan funktion ändå. Du måste definiera alla tillåtna funktioner i förväg. Du kan självklart ange både egna och PHP's funktioner. Syntaxen i din mall blir lite annorlunda, {strtoupper$title} istället för {strtoupper($title)} men det får du stå ut med. (...eller skriva om regexen själv §e )

$structure = '<dt>{strtoupper$title}</dt>
<dd>{$datetime}</dd>
<dd>{$content}</dd>
<dd>{someinvalidtransform$content}</dd>
<dd>{$someothershit}</dd>';
// De två sista raderna i mönstret är ogiltiga data i testsyfte.

$structure_allowed_items=Array('title', 'datetime', 'content');

echo getarchive('nyheter', $structure, $structure_allowed_items);

function parse_structure_item($m0, $m1, $m2, $structure, $structure_allowed_items, $row) {
	$structure_allowed_transforms=Array('strtoupper' => strtoupper);

	if (in_array($m2, $structure_allowed_items)){
		if (in_array($m1, $structure_allowed_transforms)){
			// The item and transform are valid. Replace the variable, transform the item and return the result.
			$transform = $structure_allowed_transforms[$m1];
			return htmlspecialchars($transform($row[$m2]));
		}else if(!$m1){
			// The variable is valid. Replace the variable and return the result.
			return htmlspecialchars($row[$m2]);
		}
	}

	return $m0;		// The string and/or transformation function is invalid. Return the string unmodified	
}

function getarchive ($parent, $structure, $structure_allowed_items) {
//    $sql = "SELECT * FROM archive WHERE parent = '".$parent."'";
//    $result = mysql_query($sql);

	// Testdata
	$row = Array('title' => 'Jungel-Jim', 'datetime' => '06-07/96', 'content' => 'Parsuitel Orbitelum');
    $data = NULL;

//    while($row = mysql_fetch_array($result)) {
        $datastr = preg_replace('/\{([a-z0-1_]+)?\$([a-z0-1_]+)\}/ie', 
            'parse_structure_item(\'\0\', \'\1\', \'\2\', $structure, $structure_allowed_items, $row);',
            $structure);

        $data .= $datastr;
//    }

    return $data;

}
Medlem sedan nov. 20016 480 inlägg
#5

Nice! Tack!

Nu funkar det precis som jag vill ha det :D

Tänkte bygga på en optional kommentars-funktion till mitt arkiv, men om det dyker upp problem så kanske jag återkommer.

Tack för hjälpen igen!

262 ms totalt · 4 externa anrop · v20260731065814-full.1dc6f849
120 ms — deklarationer (db)
0 ms — hämta statistik (cache)
132 ms — hämta tråd, inlägg och bilagor (db)
127 ms — ändringar (db)